非阻塞模式 Socket 连接

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;

class Target {

    InetSocketAddress address;
    SocketChannel channel;
    Exception failure;
    long connectStart;
    long connectFinish = 0;
    boolean shown = false;

    Target(String host) {
        try {
            address = new InetSocketAddress(InetAddress.getByName(host), 80);
        }
        catch (IOException e) {
            failure = e;
        }
    }

    void show() {
        String result;
        if(connectFinish != 0) {
            result = Long.toString(connectFinish - connectStart) + "ms";
         }
        else if(failure != null) {
            result = failure.toString();
        }
        else {
            result = "Timed out";
        }
        System.out.println(address + ":" + result);
        shown = true;
    }
}

public class PingClient {

    private Selector selector;
    private LinkedList<Target> targets = new LinkedList<Target>();
    private LinkedList<Target> finishedTargets = new LinkedList<Target>();

    boolean shutdown = false;

    public PingClient() throws IOException {

        selector = Selector.open();
        Connector connector = new Connector();
        Printer printer = new Printer();
        connector.start();
        printer.start();
        receiveTarget();

    }

    public static void main(String[] args) throws IOException {

        new PingClient();
    }

    public void addTarget(Target target) {

        SocketChannel socketChannel = null;
        try {
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(target.address);

            target.channel = socketChannel;
            target.connectStart = System.currentTimeMillis();

            synchronized(targets) {
                targets.add(target);
            }
            selector.wakeup();

        }
        catch (Exception e) {
            if(socketChannel != null) {
                try {
                    socketChannel.close();
                }
                catch (IOException ex) {

                }
            }
            target.failure = e;
            addFinishedTarget(target);
        }
    }

    public void addFinishedTarget(Target target) {

        synchronized(finishedTargets) {
            finishedTargets.notify();
            finishedTargets.add(target);
        }
    }

    public void printFinishedTargets() {

        try {
            for(;;) {
                Target target = null;
                synchronized(finishedTargets) {
                    while(finishedTargets.size() == 0){
                        finishedTargets.wait();
                    }
                    target = (Target) finishedTargets.removeFirst();
                }
                target.show();
            }
        }
        catch (InterruptedException e) {
            return;
        }
    }

    public void registerTargets() {

        synchronized(targets) {
            while(targets.size() > 0) {
                Target target = (Target) targets.removeFirst();

                try {
                    target.channel.register(selector, SelectionKey.OP_CONNECT, target);
                }
                catch (IOException e) {
                    try {
                        target.channel.close();
                    }
                    catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    target.failure = e;
                    addFinishedTarget(target);
                }
            }
        }
    }

    public void processSelectedKeys() {

        for(Iterator<SelectionKey> it = selector.selectedKeys().iterator(); it.hasNext();) {
            SelectionKey selectionKey = it.next();
            it.remove();

            Target target = (Target) selectionKey.attachment();
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

            try {
                if(socketChannel.finishConnect()) {
                    selectionKey.cancel();
                    target.connectFinish = System.currentTimeMillis();
                    socketChannel.close();
                    addFinishedTarget(target);
                }
            }
            catch (IOException e) {
                try {
                    socketChannel.close();
                }
                catch (IOException ex) {
                    ex.printStackTrace();
                }
                target.failure = e;
                addFinishedTarget(target);
            }
        }
    }

    public void receiveTarget() {

        try {
            BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
            String host = null;
            while((host = localReader.readLine()) != null) {
                if(!host.equals("bye")) {
                    Target target = new Target(host);
                    addTarget(target);
                }
                else {
                    shutdown = true;
                    selector.wakeup();
                    break;
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public class Printer extends Thread {

        public Printer() {
            setDaemon(true);
        }

        public void run() {
            printFinishedTargets();
        }
    }

    public class Connector extends Thread {

        public void run() {
            while(! shutdown) {
                try {
                    registerTargets();
                    if(selector.select() > 0) {
                        processSelectedKeys();
                    }
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }

            try {
                selector.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
时间: 2024-12-14 19:08:00

非阻塞模式 Socket 连接的相关文章

看到关于socket非阻塞模式设置方式记录一下。

关于socket的阻塞与非阻塞模式以及它们之间的优缺点,这已经没什么可言的:我打个很简单的比方,如果你调用socket send函数时: 如果是阻塞模式下: send先比较待发送数据的长度len和套接字s的发送缓冲的长度,如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR:如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么

服务器编程心得(四)—— 如何将socket设置为非阻塞模式

1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ int type, _In_ int protocol ); SOCKET WSASocket( _In_ int af, _In_ int type, _In_ int protocol, _In_ LPWSAPROTOCOL_INFO lpProtocolInfo, _In_ GROUP g,

非阻塞模式(ioctlsocket)

1 //Server.cpp 2 #include <stdio.h> 3 #include <winsock2.h> //winsock.h (2种套接字版本) 4 #pragma comment(lib,"ws2_32.lib") //wsock32.lib 5 6 #define MAXSIZE 100 // 7 8 int main() 9 { 10 // 11 int retVal; 12 13 char buf[MAXSIZE]; 14 15 //初

深入 CSocket 编程之阻塞和非阻塞模式

有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server (客户端 / 服务端)的网络聊天和传输文件的程序 ( 详见: 源代码参考 ) ,在调试这些程序的过程中,追踪深入至 CSocket 类核心源码 Sockcore.cpp , 对于CSocket 类的运行机制可谓是一览无遗,并且对于阻塞和非阻塞方式下的 socket 程序的编写也是稍有体会. 阅读本

非阻塞模式下connect 成功失败判断

将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK; 即: flags = fcntl(sockfd, F_GETFL, 0);                        //获取文件的flags值. fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);   //设置成非阻塞模式: 同时在接收和发送数据时,需要使用MS

linux非阻塞的socket EAGAIN的错误处理【转】

转自:http://blog.csdn.net/tianmohust/article/details/8691644 版权声明:本文为博主原创文章,未经博主允许不得转载. 在Linux中使用非阻塞的socket的情形下. (一)发送时 当客户通过Socket提供的send函数发送大的数据包时,就可能返回一个EAGAIN的错误.该错误产生的原因是由于send 函数中的size变量大小超过了tcp_sendspace的值.tcp_sendspace定义了应用在调用send之前能够在kernel中缓存

linux非阻塞的socket EAGAIN的错误处理

http://blog.csdn.net/tianmohust/article/details/8691644 在Linux中使用非阻塞的socket的情形下. (一)发送时 当客户通过Socket提供的send函数发送大的数据包时,就可能返回一个EAGAIN的错误.该错误产生的原因是由于send 函数中的size变量大小超过了tcp_sendspace的值.tcp_sendspace定义了应用在调用send之前能够在kernel中缓存的数据量.当应用程序在socket中设置了O_NDELAY或

delphi Winsock非阻塞模式详解

delphi Winsock非阻塞模式详解   Winsockt的TClientSocket设置ClientType的属性为ctNonBlocking.则通讯模式为非阻塞模式. ctBlocking为阻塞模式,这里说一下阻塞与非阻塞的一些区别. ctBlocking模式当客户端请求数据后,线程阻塞不继续执行,直到服务端返回数据,客户端将据需执行,并读取数据. 然而阻塞模式的缺陷还是比较大的,经常会使程序死掉或者假死.当服务端发送较大的文件时,阻塞模式基本废掉了,由于数据缓冲较小,不能及时的获取数

JavaNIO非阻塞模式

package com.java.NIO; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.c