zoukankan      html  css  js  c++  java
  • 套接字描述符在多进程和多线程下的共享

    一:概述

             在简单的回射服务例子中,客户端和服务器的交互步骤如下:

    客户从标准输入中读入一行文本,并写给服务器;

    服务器从网络输入读入这行文本,并回射给客户;

    客户从网络输入读入这行回射文本,并显示在标准输出上。下图描述了整个过程:

     

    二:多进程的str_cli

             其中客户端的str_cli函数处理客户端上的主要逻辑:从标准输入读入一行文本,写到服务器上,然后读会服务器对改行的回射,写到标准输出。

             str_cli的非阻塞版木比较复杂--约有135行代码(P342),与之相比,使用select和阻塞式IO的版木有40行代码(P137),而最初的停-等版本(P100)则只有区区20行代码。

             代码长度从20行倍增到40行的努力是值得的,因为在批最模式下执行速度几乎提高了30倍,而且在阻塞的描述符上使用select不太复杂。然而考虑到结果代码的复杂性,把应用程序编写成使用非阻塞式IO的努力足否照样值得?答案是否定的。每当我们发现需要使用非阻塞式IO时,更简单的办法通常是把应用程序仟务划分到多个迸程〔使用Fork〕或多个线程。

             下面是使用多进程的版本:


    #include     "unp.h"                                                 

                                                                         

    void  str_cli(FILE  *fp,  int sockfd)                                        

    {                                                                     

        pid_t    pid;                                                   

        char    sendline[MAXLINE],  recvline[MAXLINE];                   

                                                                         

        if ( (pid = Fork()) == 0) {   /* child: server -> stdout */      

           while (Readline(sockfd,  recvline,  MAXLINE) > 0)               

               Fputs(recvline,  stdout);                                  

                                                                          

           kill(getppid(),  SIGTERM);   /* in case parent still running */

           exit(0);                                                      

        }                                                                

                                                                          

        /* parent: stdin -> server */                                    

        while (Fgets(sendline,  MAXLINE,  fp) != NULL)                     

            Writen(sockfd,  sendline,  strlen(sendline));                  

                                                                         

        Shutdown(sockfd,  SHUT_WR); /* EOF on stdin, send FIN */         

        pause();                                                         

        return;                                                          

    }                                                                    

     

     

             图中明确地指出:所用TCP连接是全双工的,而且父子进程共享同一个套接字:父进程往该套接字中写,子进程从该套接字中读。尽管套接字只有一个,其接收缓冲区和发送缓冲区也分别只有一个,然而这个套接字却有两个描述符在引用它:一个在父进程中,另一个在子进程中。

     

    三:多线程的echo服务器

    #include     "unpthread.h"                                              

                                                                            

    static  void  *doit(void*);      /* each thread executes thisfunction */

                                                                            

    int  main(int argc,  char **argv)                                             

    {                                                                       

        int    listenfd,  connfd;                                           

        pthread_t  tid;                                                      

        socklen_t  addrlen,  len;                                             

        struct  sockaddr  *cliaddr;                                            

                                                                            

        if (argc == 2)                                                      

            listenfd = Tcp_listen(NULL,  argv[1],  &addrlen);                 

        else if (argc == 3)                                                 

            listenfd = Tcp_listen(argv[1],  argv[2],  &addrlen);              

        else                                                                

            err_quit("usage: tcpserv01 [<host> ] <service or port>");      

                                                                            

        cliaddr = malloc(addrlen);                                          

        for (; ; ) {                                                        

            len = addrlen;                                                  

            connfd = Accept(listenfd,  cliaddr,  &len);                       

            Pthread_create(&tid,  NULL,  &doit, (void *) connfd);             

        }                                                                    

    }                                                                       

                                                                            

    static void *  doit(void * arg)                                                         

    {                                                                       

        Pthread_detach(pthread_self());                                     

        str_echo((int) arg);        /* same function as before */           

        Close((int) arg);           /* done with connected socket*/        

        return (NULL);                                                      

    }                                                                                     

     

     

             注意:主线程不关闭已连接套接字,而在调用fork的并发服务器程序中却总是反着做。这是因为同一进程内的所有线程共享全部描述符。要是主线程调用close,它就会终止相应的连接。创建新线程并不影响己打开描述符的引用计数,这一点不同于fork

     

     

    摘自《Unix网络编程卷一:套接字联网API》

     

  • 相关阅读:
    Unity3D脚本使用:物体调用物体
    Unity3D脚本使用:游戏对象访问
    Unity3D 浏览工具
    spring的工厂方法
    spring运用的设计模式
    Jquery ajax 与 lazyload的混合使用(实现图片异步加载)
    关于线程安全的一点总结
    lazyload的使用心得
    ajax原理及应用
    $.ajax和$.load的区别
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247249.html
Copyright © 2011-2022 走看看