一、阻塞模式



      阻塞是socket的缺省方式,也是最常用的方式,即调用结果返回之前,函数阻塞,当前线程会挂 起, suspend 。


      可能造成阻塞的函数有:connect()、accept()、读写函数、gethostbyname()等。






python tcp非阻塞recv 非阻塞socket编程_python tcp非阻塞recv


二、再探 send 和 recv


  •   send 和 recv 是 socket 编程中两个核心的函数。 


 •   send 表示发送数据,其实际上并不是直接将数据发送出去,而是将数据先发送到系统对应的 socket 的缓冲区,在


    由系统使用 tcp / ip 协议进行发送。此时 send 返回的结果只是表明是否成功发送到系统的缓冲区。


  •   同样 recv 函数也是从系统的对应的 socket 缓冲区读取数据,而该缓冲区中的数据也是由协议保证的。如果该缓


    没有数据,将区别对待:如果对应的 socket 是阻塞的,则 recv 工作在阻塞模式,将一直等到缓冲区中有数据才返


    回,否则会一直挂起。




三、非阻塞模式


  •   非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。


  •   如果指定非阻塞模式,程序调用可能造成阻塞的函数时,如果会发生阻塞,这些函数返回 -1 并将 errno 设


    为 EAGAIN 或 EWOULDBLOCK ,程序可继续向下运行。可能阻塞的函数对应的任务完成,则再次调用该函数时就


    返回 0 表示运行结束。


python tcp非阻塞recv 非阻塞socket编程_应用程序_02


四、fcntl函数


       函数 fcntl () 针对 ( 文件 ) 描述符提供控制。若要改变阻塞模式,可如下调用:


       非阻塞 I/O :可将 cmd 设置为 F_SETFL ,将 lock 设置为 O_NONBLOCK 。


       异步 I/O :可将 cmd 设置为 F_SETFL ,将 lock 设置为 O_ASYNC 。


python tcp非阻塞recv 非阻塞socket编程_socket_03


五、非阻塞模式流程


• server端


while (true)

if 有新连接{

  建立并记录该新连接;

  for (所有的有效连接){

    if 该连接中有字符可读{

      读入字符串;

      for (所有其他的有效连接) {

        将该字符串发送给该连接;

      }

    }

  }

}

•  client端


while (true){


  if ( 与server的连接有字符可读 ) {


        从该连接读入 ;


         输出到标准输出上去 ;


  }


  if ( 标准输入可读 ) {


      从标准输入读入 ;


      发送 到与server的连接中去 .


  }


}




六、轮询


  •   非阻塞模式可以避免程序死锁,但是需要程序不断检查各个可能阻塞的函数的状态,当一个应用程序使用了非阻


      塞模式的套接字,它需要使用一个循环来不听的测试是否一个文件描述符有数据可读(称做轮询, polling )。


   •   分析上面的程序可以知道 , 不管是 server 还是 client, 它们都不停的轮流查询各个文件描述符 , 一旦可读就读入并进


     行处理。


   •   应用程序不停的 polling 内核来检查是否 I/O 操作已经就绪,对系统资源的消耗非常大。 server 或者 client 单独执


     行时 ,CPU 资源的 98% 左右都被其占用。这将是一个极浪费 CPU 资源的操作,因此实际开发中基本不使用。


七、I/O多路复用


  •    虽然我们不希望在某一个用户没有反应时阻塞其他的用户,但我们却应该在没有任何用户有反应的情况之下停止


     程 序的运行,让出抢占的系统资源,进入阻塞状态。


  •   使用 select() 、 poll() 等函数实现对多个 socket 的同步 I/O 操作。它能同时等待多个 socket 描述符,而这些 socke题,


    述符其中的任意一个进入读就绪 / 写就绪 / 出错状态, select() 函数就可以返回。


python tcp非阻塞recv 非阻塞socket编程_socket_04


八、select函数


        select方法中,所有文件描述符都是阻塞的。使用select判断一组文件描述符中是否有一个可读(写),   如果没有


       就 阻塞 , 直到有一个的时候就被唤醒。


python tcp非阻塞recv 非阻塞socket编程_非阻塞_05


九、fd_set函数


      fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),这可以是我们所说的普通意义的


      文件,也包括Linux下任何设备、管道、FIFO、socket等。


python tcp非阻塞recv 非阻塞socket编程_编程_06



                                                                                           2013.11.21 晚上