zoukankan      html  css  js  c++  java
  • Socket 连接建立过程

    阻塞模式下:

    1,客户端向服务器端发起请求建立连接时,服务器端只需要运行到

    serverSocket = new ServerSocket(port,3);

    客户端注册的  SelectionKey.OP_CONNECT 事件就能够发生。

    也就是说,不需要等到服务器端执行到

    socket = serverSocket.accept();

    客户端注册的SelectionKey.OP_CONNECT 通过 select()查询时就返回一个 大于 0 的值了。

    2,server端未执行到

      serverSocket = new ServerSocket(port,3);

    时,client端执行了

    socket.connect(new InetSocketAddress(host, port));

    时,抛出异常:Exception in thread "main" java.net.ConnectException: Connection refused: connect

    3,server端执行了

     serverSocket = new ServerSocket(port,3);

    之后,client端执行

    socket.connect(new InetSocketAddress(host, port));

    System.out.println("connection accepted " + socket.getInetAddress() + ":" + socket.getPort());

    时,能成功执行,且输出:connection accepted localhost/127.0.0.1:8000

    然后client 能够给server发送数据。但只有到server执行了 accpet()后,才能受理client的数据。

    4,关于SocketChannel类的connect()方法作用

    当SocketChannel工作于非阻塞模式下时,调用connect()时会立即返回:如果连接建立成功则返回的是true(比如连接localhost时,能立即建立起连接),否则返回false。在非阻塞模式下,返回false后,必须要在随后的某个地方调用finishConnect()方法完成连接。

    当SocketChannel处于阻塞模式下时,调用connect()时会进入阻塞,直至连接建立成功或者发生IO错误时,才从阻塞状态中退出。

    5,Selector.select()方法从阻塞状态返回的详细过程 和 ServerSocket.accpet()方法从阻塞状态返回的过程

    select()方法:如果事件注册或者已经注册的事件没有发生。调用select()方法的线程将会被阻塞。该线程可以通过如下方法退出阻塞状态:

    ①其他线程执行了同一个Selector的wakeup()方法将之唤醒,在这种情况下,select()返回值为0。表明它是被wakeup()唤醒的,而不是因为有注册的事件发生了而唤醒的。

    ②注册到Selector上的事件发生了。此时,线程也会从阻塞状态中退出,并且select()方法返回一个非0值,代表发生的事件的数目。

    参考一段代码:

    1 while(!shutdown){
    2                 try{
    3                     registerTargets();
    4                     if(selector.select() > 0)
    5                         processSelectedKeys();
    6                 }catch(Exception e){
    7                     e.printStackTrace();
    8                 }
    9             }

    假设线程A执行到第4行的if语句中的select()方法时,进入了阻塞状态:

    如果另外一个线程执行 selector.wakeup() 。该线程(线程A)将会被唤醒,然后select()方法返回一个0值(表示没有注册的事件发生),执行if判断,if语句就会不成立,继续下一轮while循环。-----先从select()方法中返回,再执行if判断----“验证了程序总是从段点处往下执行的!!!”

    accept()方法从阻塞状态返回的具体细节---假设通道工作在阻塞模式。

    当serverSocketChannel.acppet()执行时,若此时没有连接请求到来(准确地说应该是:操作系统管理的连接请求队列为空),线程就会进入阻塞状态。直到下面情况时,从阻塞状态返回:

    ①被其他线程中断了--不详细讨论

    ②连接请求到来了(操作系统管理的连接请求队列中有数据了),线程从accept()退出阻塞状态的同时返回一个SocketChannel对象。这个对象就表示:从客户端到服务器端建立起的一条TCP连接。

    6,当Selector中注册的事件发生时,底层发生了什么操作?

    以OP_ACCEPT事件为例讨论:JDK中关于该事件的注释如下:

    Suppose that a selection key's interest set contains OP_ACCEPT at the start of a selection operation. If the selector detects that the corresponding server-socket channel is ready to accept another connection, or has an error pending, then it will add OP_ACCEPT to the key's ready set and add the key to its selected-key set.

    首先,selection key的感兴趣的集合中要包含OP_ACCEPT,也即,要把OP_ACCEPT事件注册到Selector中,代码如下:

    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    其次,注册了之后,由selector来 detect---检测 相应的 server-socket 通道是否已经准备好接收其他的连接请求,如果准备好了:

    就会把OP_ACCEPT添加到这个SelectionKey对象的 就绪事件集合(ready set)中,同时,再把这个SelectionKey对象添加到已选择的Key集合(selected-key set)中。

    注意:上面的过程涉及到了两个集合:一个是事件的集合,另一个是SelectionKey对象的集合。明显这两个集合是不同的。事件一共只有如下四种:

    public static final int OP_ACCEPT = 1 << 4;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_WRITE = 1 << 2;

    事件的集合是附属在某个SelectionKey对象上的。也即,一个SelectionKey对象就拥有一个事件集合。

    SelectionKey集合分以下三种:

    已注册的键的集合(Registered key set)
    已选择的键的集合(Selected key set)
    已取消的键的集合(Cancelled key set)

    如上面所说,如果selector检测到了通道准备好了接收其他的连接请求,就会把相应的SelectionKey对象添加到已选择的键集合中。

  • 相关阅读:
    ORDER BY子句
    SELECT子句
    WHERE子句
    定义数据完整性
    Microsoft Visual Studio Tips
    zz人性的经典总结54句
    About Refactor
    zz你的交际力能否通吃?
    zz一个高级主管必须明白的几点事情
    About SQLServer Transaction
  • 原文地址:https://www.cnblogs.com/hapjin/p/5146631.html
Copyright © 2011-2022 走看看