Linux网络编程 - TCP高级应用:多路复用



文件I/O方式比较

1. 阻塞式文件IO

2. 非阻塞式文件IO

3. 多路复用IO


4. 信号驱动IO(也叫驱动异步IO)


IO阻塞与非阻塞操作

阻塞:如果没有数据可操作,该函数调用将阻塞,导致对应进程暂停执行,当有数据继续执行并返回。
默认read/write函数,以及recv/send函数采用阻塞方式

非阻塞:需要进程立即返回,则需要设置为非阻塞方式,即如果没有数据可接收就立即返回-1表示接收失败,并修改系统全局变量errno。

socket读写,以非阻塞方式调用recv()函数返回时,没有数据可读,将修改errno变量的值为“EAGAIN”,表示recv读数据时,对方没有发送数据过来。


非阻塞应用示例

发送端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <sys/socket.h>  
  5. #include <resolv.h>  
  6. #include <stdlib.h>  
  7. #include <netinet/in.h>  
  8. #include <arpa/inet.h>  
  9. #include <unistd.h>  
  10. #include <fcntl.h>  
  11. #define MAXBUF 128  
  12.   
  13. int main(int argc, char **argv)  
  14. {  
  15.     int sockfd, ret, i;  
  16.     struct sockaddr_in dest, mine;  
  17.     char buffer[MAXBUF + 1];      
  18.   
  19.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  20.     {  
  21.         perror("Socket");  
  22.         exit(EXIT_FAILURE);  
  23.     }  
  24.   
  25.     bzero(&dest, sizeof(dest));  
  26.     dest.sin_family = AF_INET;  
  27.     dest.sin_port = htons(7838);  
  28.       
  29.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)  
  30.     {  
  31.         perror(argv[1]);  
  32.         exit(EXIT_FAILURE);  
  33.     }  
  34.   
  35.     bzero(&mine, sizeof(mine));  
  36.     mine.sin_family = AF_INET;  
  37.     mine.sin_port = htons(7839);  
  38.   
  39.     if (inet_aton(argv[2], (struct in_addr *) &mine.sin_addr.s_addr) == 0)  
  40.     {  
  41.         perror(argv[2]);  
  42.         exit(EXIT_FAILURE);  
  43.     }  
  44.     if (bind(sockfd, (struct sockaddr *) &mine, sizeof(struct sockaddr)) == -1)  
  45.     {  
  46.         perror(argv[3]);  
  47.         exit(EXIT_FAILURE);  
  48.     }  
  49.   
  50.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)   
  51.     {  
  52.         perror("Connect ");  
  53.         exit(EXIT_FAILURE);  
  54.     }     
  55.   
  56.     if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1)   
  57.     {  
  58.         perror("fcntl");  
  59.         exit(EXIT_FAILURE);  
  60.     }  
  61.       
  62.     while(1)  
  63.     {  
  64.         bzero(buffer, MAXBUF + 1);  
  65.         ret = recv(sockfd, buffer, MAXBUF, 0);  
  66.         if(ret > 0)  
  67.         {  
  68.             printf("get %d message:%s", ret, buffer);  
  69.             ret=0;  
  70.         }  
  71.         else if(ret < 0)   
  72.         {  
  73.             if(errno == EAGAIN)   
  74.             {  
  75.                 errno=0;  
  76.                 continue;  
  77.             }  
  78.             else  
  79.             {  
  80.                 perror("recv");  
  81.                 exit(EXIT_FAILURE);  
  82.             }  
  83.         }  
  84.         memset( buffer,'\0',MAXBUF+1);  
  85.         printf("input message to send:");  
  86.         fgets( buffer,MAXBUF,stdin);  
  87.         if((ret=send(sockfd,buffer,strlen(buffer),0))==-1)  
  88.         {  
  89.             perror("send");  
  90.             exit(EXIT_FAILURE);  
  91.         }  
  92.     }  
  93.     close(sockfd);  
  94.     return 0;  
  95. }  
接收端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <netinet/in.h>  
  6. #include <arpa/inet.h>  
  7. #include <unistd.h>  
  8. #include <stdlib.h>  
  9. #include <errno.h>  
  10. #define  BUFSIZE 128  
  11.   
  12. int main(int argc,char *argv[])  
  13. {  
  14.     int server_sockfd, client_sockfd;  
  15.     int server_len, client_len;  
  16.     struct sockaddr_in server_address;  
  17.     struct sockaddr_in client_address;  
  18.     int i,byte;  
  19.     char char_send[BUFSIZE];  
  20.   
  21.     server_sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  22.     server_address.sin_family = AF_INET;  
  23.     if (inet_aton(argv[1], (struct in_addr *) & server_address.sin_addr.s_addr) == 0)  
  24.     {  
  25.         perror(argv[1]);  
  26.         exit(EXIT_FAILURE);  
  27.     }  
  28.     server_address.sin_port = htons(7838);  
  29.     server_len = sizeof(server_address);  
  30.   
  31.     bind(server_sockfd, (struct sockaddr *)&server_address, server_len);  
  32.     listen(server_sockfd, 5);  
  33.     printf("server waiting for connect\n");  
  34.   
  35.     client_len = sizeof(client_address);  
  36.     client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);  
  37.   
  38.     for(i=0;i<5;i++)  
  39.     {  
  40.         memset(char_send,'\0',BUFSIZE);  
  41.         printf("input message to send:");  
  42.         fgets(char_send,BUFSIZE,stdin);  
  43.   
  44.         if((byte=send(client_sockfd,char_send,strlen(char_send),0))==-1)  
  45.         {  
  46.             perror("send");  
  47.             exit(EXIT_FAILURE);  
  48.         }  
  49.         memset(char_send,'\0',BUFSIZE);  
  50.         byte = recv(client_sockfd, char_send, BUFSIZE,MSG_DONTWAIT);  
  51.   
  52.         if(byte > 0)  
  53.         {  
  54.             printf("get %d message:%s", byte, char_send);  
  55.             byte=0;  
  56.         }  
  57.         else if(byte<0)  
  58.         {  
  59.             if(errno==EAGAIN)  
  60.             {  
  61.                 errno=0;  
  62.                 continue;  
  63.             }  
  64.             else  
  65.             {  
  66.                 perror("recv");  
  67.                 exit(EXIT_FAILURE);  
  68.             }  
  69.         }  
  70.     }     
  71.     shutdown(client_sockfd,2);  
  72.     shutdown(server_sockfd,2);  
  73. }  
发送端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_unblock_server 172.18.229.62  
  2. server waiting for connect  
  3. input message to send:hello  
  4. input message to send:test  
  5. get 3 message:hi  
  6. input message to send:go  
  7. input message to send:read  
  8. input message to send:why  
接收端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_unblock_client 172.18.229.62 172.18.229.62  
  2. get 6 message:hello  
  3. input message to send:hi  
  4. get 5 message:test  
  5. input message to send:go  
  6. get 12 message:go  
  7. read  
  8. why  
  9. input message to send:hi  
socket多路复用应用

select函数

select提供轮循等待的方式从多个文件描述符中获取状态发变后的消息 。


第1个参数指定要检测的文件描述符的范围。测试范围在0到nfds−1之间的文件描述符(nfds=这些文件描述符中的最大值+1)。
第2、3、4三个参数类型都是fd_set *。这三个参数都是文件描述符的集合。
dfds包含所有因状态变成可读而触发select()函数返回的文件描述符;
wtfds包含所有因状态变成可写而触发select()函数返回的文件描述符;
exfds包含所有因状态发生特殊异常(例如带外数据到来)而触发select()函数返回的文件描述符 

文件描述符集合操作 

最后一个参数timeout显然是一个超时时限,其类型是struct timeval * 。


如果函数执行错误,将返回-1;
如果因超时而返回,即在timeout所描述的时间范围内没有任何描述符出现异常,则返回0;
如果因一个或多个文件描述符异常而返回,其返回值为产生异常的文件描述符数,并在相应文件描述符集合中清除未产生异常的文件描述符记录,因此,返回后可以根据文件描述符集合的记录查找出是哪一个文件描述符返回。

基本示例

检测某个socket是否有数据可读


pselect函数


poll与ppoll函数

poll函数

poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <poll.h>  
  2. int poll(struct pollfd *fd, nfds_t nfds, int timeout);  
    参数:
   1)第一个参数:一个结构数组,struct pollfd结构如下:
[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. struct pollfd{  
  2. int fd;              //文件描述符  
  3. short events;    //请求的事件  
  4. short revents;   //返回的事件  
  5. };  
  events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件,poll用已经发生的事件填充revents。poll函数通过在revents中设置标志肌肤POLLHUP、POLLERR和POLLNVAL来反映相关条件的存在。不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUN或返回0字节的常规读操作来传达。即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作。
poll函数的事件标志符值
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
  注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
  2)第二个参数nfds:要监视的描述符的数目。
  3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。
timeout值 说明
INFTIM 永远等待
0 立即返回,不阻塞进程
>0 等待指定数目的毫秒数

ppoll函数

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <poll.h>  
  2. int ppoll(struct pollfd *fd, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);  

与pselect一样,ppoll函数可以在阻塞过程中屏蔽某些信号,而在timeout时间上,ppoll的时间精度更高。

多路复用应用示例

服务器代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <stdlib.h>  
  4.   
  5. #include <errno.h>  
  6.   
  7. #include <string.h>  
  8.   
  9. #include <sys/types.h>  
  10.   
  11. #include <netinet/in.h>  
  12.   
  13. #include <sys/socket.h>  
  14.   
  15. #include <sys/wait.h>  
  16.   
  17. #include <unistd.h>  
  18.   
  19. #include <arpa/inet.h>  
  20.   
  21. #include <sys/time.h>  
  22.   
  23. #include <sys/types.h>  
  24.   
  25.   
  26.   
  27. #define MAXBUF 1024  
  28.   
  29.   
  30.   
  31. int main(int argc, char **argv)  
  32.   
  33. {  
  34.   
  35.         int sockfd, new_fd;  
  36.   
  37.         socklen_t len;  
  38.   
  39.         struct sockaddr_in my_addr, their_addr;  
  40.   
  41.         unsigned int myport, lisnum;  
  42.   
  43.         char buf[MAXBUF + 1];  
  44.   
  45.         fd_set rfds;  
  46.   
  47.         struct timeval tv;  
  48.   
  49.         int retval, maxfd = -1;  
  50.   
  51.   
  52.   
  53.         if (argv[2])  
  54.   
  55.                 myport = atoi(argv[2]);  
  56.   
  57.         else  
  58.   
  59.                 myport = 7838;  
  60.   
  61.         if (argv[3])  
  62.   
  63.                 lisnum = atoi(argv[3]);  
  64.   
  65.         else  
  66.   
  67.                 lisnum = 2;  
  68.   
  69.         if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {  
  70.   
  71.                 perror("socket");  
  72.   
  73.                 exit(EXIT_FAILURE);  
  74.   
  75.         }  
  76.   
  77.   
  78.   
  79.         bzero(&my_addr, sizeof(my_addr));  
  80.   
  81.         my_addr.sin_family = PF_INET;  
  82.   
  83.         my_addr.sin_port = htons(myport);  
  84.   
  85.         if (argv[1])  
  86.   
  87.             my_addr.sin_addr.s_addr = inet_addr(argv[1]);  
  88.   
  89.         else  
  90.   
  91.             my_addr.sin_addr.s_addr = INADDR_ANY;  
  92.   
  93.         if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {  
  94.   
  95.            perror("bind");  
  96.   
  97.            exit(EXIT_FAILURE);  
  98.   
  99.         }  
  100.   
  101.          if (listen(sockfd, lisnum) == -1) {  
  102.   
  103.             perror("listen");  
  104.   
  105.             exit(EXIT_FAILURE);  
  106.   
  107.          }  
  108.   
  109.   
  110.   
  111.          while (1)   
  112.   
  113.          {  
  114.   
  115.             printf ("\n----wait for new connect\n");  
  116.   
  117.             len = sizeof(struct sockaddr);  
  118.   
  119.             if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) {  
  120.   
  121.                 perror("accept");  
  122.   
  123.                 exit(errno);  
  124.   
  125.             } else  
  126.   
  127.                 printf("server: got connection from %s, port %d, socket %d\n",   
  128.   
  129.                         inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);  
  130.   
  131.             while (1)   
  132.   
  133.             {  
  134.   
  135.                 FD_ZERO(&rfds);  
  136.   
  137.                 FD_SET(0, &rfds);  
  138.   
  139.                 FD_SET(new_fd, &rfds);  
  140.   
  141.                 maxfd = new_fd;  
  142.   
  143.                 tv.tv_sec = 1;  
  144.   
  145.                 tv.tv_usec = 0;  
  146.   
  147.                 retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  148.   
  149.                 if (retval == -1)   
  150.   
  151.                 {  
  152.   
  153.                     perror("select");  
  154.   
  155.                     exit(EXIT_FAILURE);  
  156.   
  157.                 } else if (retval == 0) {  
  158.   
  159.                         continue;  
  160.   
  161.                 }   
  162.   
  163.                 else  
  164.   
  165.                 {  
  166.   
  167.                     if (FD_ISSET(0, &rfds))  
  168.   
  169.                     {  
  170.   
  171.                             bzero(buf, MAXBUF + 1);  
  172.   
  173.                             fgets(buf, MAXBUF, stdin);  
  174.   
  175.                             if (!strncasecmp(buf, "quit", 4)) {  
  176.   
  177.                                 printf("i will quit!\n");  
  178.   
  179.                                 break;  
  180.   
  181.                             }  
  182.   
  183.                             len = send(new_fd, buf, strlen(buf) - 1, 0);  
  184.   
  185.                             if (len > 0)  
  186.   
  187.                                 printf ("send successful,%d byte send!\n",len);  
  188.   
  189.                             else {  
  190.   
  191.                                 printf("send failure!");  
  192.   
  193.                                 break;  
  194.   
  195.                             }  
  196.   
  197.                     }  
  198.   
  199.                     if (FD_ISSET(new_fd, &rfds))   
  200.   
  201.                     {   
  202.   
  203.                             bzero(buf, MAXBUF + 1);  
  204.   
  205.                             len = recv(new_fd, buf, MAXBUF, 0);  
  206.   
  207.                             if (len > 0)  
  208.   
  209.                                 printf ("recv success :'%s',%dbyte recv\n", buf, len);  
  210.   
  211.                             else  
  212.   
  213.                             {  
  214.   
  215.                                 if (len < 0)  
  216.   
  217.                                     printf("recv failure\n");  
  218.   
  219.                                 else  
  220.   
  221.                                 {  
  222.   
  223.                                     printf("the ohter one end ,quit\n");  
  224.   
  225.                                     break;  
  226.   
  227.                                 }  
  228.   
  229.                             }  
  230.   
  231.                     }  
  232.   
  233.                  }  
  234.   
  235.             }  
  236.   
  237.             close(new_fd);  
  238.   
  239.             printf("need othe connecdt (no->quit)");  
  240.   
  241.             fflush(stdout);  
  242.   
  243.             bzero(buf, MAXBUF + 1);  
  244.   
  245.             fgets(buf, MAXBUF, stdin);  
  246.   
  247.             if (!strncasecmp(buf, "no", 2))   
  248.   
  249.             {  
  250.   
  251.                 printf("quit!\n");  
  252.   
  253.                 break;  
  254.   
  255.             }  
  256.   
  257.         }  
  258.   
  259.         close(sockfd);  
  260.   
  261.         return 0;  
  262.   
  263. }  

客户端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <string.h>  
  4.   
  5. #include <errno.h>  
  6.   
  7. #include <sys/socket.h>  
  8.   
  9. #include <resolv.h>  
  10.   
  11. #include <stdlib.h>  
  12.   
  13. #include <netinet/in.h>  
  14.   
  15. #include <arpa/inet.h>  
  16.   
  17. #include <unistd.h>  
  18.   
  19. #include <sys/time.h>  
  20.   
  21. #include <sys/types.h>  
  22.   
  23.   
  24.   
  25. #define MAXBUF 1024  
  26.   
  27. int main(int argc, char **argv)  
  28.   
  29. {  
  30.   
  31.     int sockfd, len;  
  32.   
  33.     struct sockaddr_in dest;  
  34.   
  35.     char buffer[MAXBUF + 1];  
  36.   
  37.     fd_set rfds;  
  38.   
  39.     struct timeval tv;  
  40.   
  41.     int retval, maxfd = -1;  
  42.   
  43.   
  44.   
  45.     if (argc != 3)   
  46.   
  47.     {  
  48.   
  49.         printf("argv format errno,pls:\n\t\t%s IP port\n",argv[0], argv[0]);  
  50.   
  51.         exit(EXIT_FAILURE);  
  52.   
  53.     }  
  54.   
  55.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  56.   
  57.     {  
  58.   
  59.         perror("Socket");  
  60.   
  61.         exit(EXIT_FAILURE);  
  62.   
  63.     }  
  64.   
  65.   
  66.   
  67.     bzero(&dest, sizeof(dest));  
  68.   
  69.     dest.sin_family = AF_INET;  
  70.   
  71.     dest.sin_port = htons(atoi(argv[2]));  
  72.   
  73.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)   
  74.   
  75.     {  
  76.   
  77.         perror(argv[1]);  
  78.   
  79.         exit(EXIT_FAILURE);  
  80.   
  81.     }  
  82.   
  83.   
  84.   
  85.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)   
  86.   
  87.     {  
  88.   
  89.         perror("Connect ");  
  90.   
  91.         exit(EXIT_FAILURE);  
  92.   
  93.     }  
  94.   
  95.   
  96.   
  97.     printf("\nget ready pls chat\n");  
  98.   
  99.     while (1)   
  100.   
  101.     {  
  102.   
  103.         FD_ZERO(&rfds);  
  104.   
  105.         FD_SET(0, &rfds);  
  106.   
  107.         FD_SET(sockfd, &rfds);  
  108.   
  109.         maxfd = sockfd;  
  110.   
  111.         tv.tv_sec = 1;  
  112.   
  113.         tv.tv_usec = 0;  
  114.   
  115.         retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  116.   
  117.         if (retval == -1)   
  118.   
  119.         {  
  120.   
  121.             printf("select %s", strerror(errno));  
  122.   
  123.             break;  
  124.   
  125.         }   
  126.   
  127.         else if (retval == 0)  
  128.   
  129.             continue;  
  130.   
  131.         else  
  132.   
  133.         {  
  134.   
  135.             if (FD_ISSET(sockfd, &rfds))   
  136.   
  137.             {  
  138.   
  139.                 bzero(buffer, MAXBUF + 1);  
  140.   
  141.                 len = recv(sockfd, buffer, MAXBUF, 0);  
  142.   
  143.                 if (len > 0)  
  144.   
  145.                     printf ("recv message:'%s',%d byte recv\n",buffer, len);  
  146.   
  147.                 else   
  148.   
  149.                 {  
  150.   
  151.                     if (len < 0)  
  152.   
  153.                         printf ("message recv failure\n");  
  154.   
  155.                     else  
  156.   
  157.                     {  
  158.   
  159.                         printf("the othe quit ,quit\n");  
  160.   
  161.                         break;  
  162.   
  163.                     }  
  164.   
  165.                 }  
  166.   
  167.             }  
  168.   
  169.             if (FD_ISSET(0, &rfds))   
  170.   
  171.             {  
  172.   
  173.                 bzero(buffer, MAXBUF + 1);  
  174.   
  175.                 fgets(buffer, MAXBUF, stdin);  
  176.   
  177.                 if (!strncasecmp(buffer, "quit", 4)) {  
  178.   
  179.                     printf("i will quit\n");  
  180.   
  181.                     break;  
  182.   
  183.                 }  
  184.   
  185.                 len = send(sockfd, buffer, strlen(buffer) - 1, 0);  
  186.   
  187.                 if (len < 0) {  
  188.   
  189.                     printf ("message send failure");  
  190.   
  191.                     break;  
  192.   
  193.                 } else  
  194.   
  195.                     printf  
  196.   
  197.                         ("send success,%d byte send\n",len);  
  198.   
  199.             }  
  200.   
  201.         }  
  202.   
  203.     }  
  204.   
  205.     close(sockfd);  
  206.   
  207.     return 0;  
  208.   
  209. }   
服务器运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_sy_chat_server 172.18.229.62 8000  
  2.   
  3. ----wait for new connect  
  4. server: got connection from 172.18.229.62, port 55410, socket 4  
  5. recv success :'hello',5byte recv  
  6. recv success :'test',4byte recv  
  7. recv success :'why',3byte recv  
  8. ready  
  9. send successful,5 byte send!  
  10. end  
  11. send successful,3 byte send!  
  12. quit  
  13. i will quit!  
  14. need othe connecdt (no->quit)no  
  15. quit!  
客户端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_sy_chat_client 172.18.229.62 8000  
  2.   
  3. get ready pls chat  
  4. hello  
  5. send success,5 byte send  
  6. test  
  7. send success,4 byte send  
  8. why  
  9. send success,3 byte send  
  10. recv message:'ready',5 byte recv  
  11. recv message:'end',3 byte recv  
  12. the othe quit ,quit  

原文链接

http://blog.csdn.net/geng823/article/details/41750405

文件I/O方式比较

1. 阻塞式文件IO

2. 非阻塞式文件IO

3. 多路复用IO


4. 信号驱动IO(也叫驱动异步IO)


IO阻塞与非阻塞操作

阻塞:如果没有数据可操作,该函数调用将阻塞,导致对应进程暂停执行,当有数据继续执行并返回。
默认read/write函数,以及recv/send函数采用阻塞方式

非阻塞:需要进程立即返回,则需要设置为非阻塞方式,即如果没有数据可接收就立即返回-1表示接收失败,并修改系统全局变量errno。

socket读写,以非阻塞方式调用recv()函数返回时,没有数据可读,将修改errno变量的值为“EAGAIN”,表示recv读数据时,对方没有发送数据过来。


非阻塞应用示例

发送端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <sys/socket.h>  
  5. #include <resolv.h>  
  6. #include <stdlib.h>  
  7. #include <netinet/in.h>  
  8. #include <arpa/inet.h>  
  9. #include <unistd.h>  
  10. #include <fcntl.h>  
  11. #define MAXBUF 128  
  12.   
  13. int main(int argc, char **argv)  
  14. {  
  15.     int sockfd, ret, i;  
  16.     struct sockaddr_in dest, mine;  
  17.     char buffer[MAXBUF + 1];      
  18.   
  19.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  20.     {  
  21.         perror("Socket");  
  22.         exit(EXIT_FAILURE);  
  23.     }  
  24.   
  25.     bzero(&dest, sizeof(dest));  
  26.     dest.sin_family = AF_INET;  
  27.     dest.sin_port = htons(7838);  
  28.       
  29.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)  
  30.     {  
  31.         perror(argv[1]);  
  32.         exit(EXIT_FAILURE);  
  33.     }  
  34.   
  35.     bzero(&mine, sizeof(mine));  
  36.     mine.sin_family = AF_INET;  
  37.     mine.sin_port = htons(7839);  
  38.   
  39.     if (inet_aton(argv[2], (struct in_addr *) &mine.sin_addr.s_addr) == 0)  
  40.     {  
  41.         perror(argv[2]);  
  42.         exit(EXIT_FAILURE);  
  43.     }  
  44.     if (bind(sockfd, (struct sockaddr *) &mine, sizeof(struct sockaddr)) == -1)  
  45.     {  
  46.         perror(argv[3]);  
  47.         exit(EXIT_FAILURE);  
  48.     }  
  49.   
  50.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)   
  51.     {  
  52.         perror("Connect ");  
  53.         exit(EXIT_FAILURE);  
  54.     }     
  55.   
  56.     if(fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1)   
  57.     {  
  58.         perror("fcntl");  
  59.         exit(EXIT_FAILURE);  
  60.     }  
  61.       
  62.     while(1)  
  63.     {  
  64.         bzero(buffer, MAXBUF + 1);  
  65.         ret = recv(sockfd, buffer, MAXBUF, 0);  
  66.         if(ret > 0)  
  67.         {  
  68.             printf("get %d message:%s", ret, buffer);  
  69.             ret=0;  
  70.         }  
  71.         else if(ret < 0)   
  72.         {  
  73.             if(errno == EAGAIN)   
  74.             {  
  75.                 errno=0;  
  76.                 continue;  
  77.             }  
  78.             else  
  79.             {  
  80.                 perror("recv");  
  81.                 exit(EXIT_FAILURE);  
  82.             }  
  83.         }  
  84.         memset( buffer,'\0',MAXBUF+1);  
  85.         printf("input message to send:");  
  86.         fgets( buffer,MAXBUF,stdin);  
  87.         if((ret=send(sockfd,buffer,strlen(buffer),0))==-1)  
  88.         {  
  89.             perror("send");  
  90.             exit(EXIT_FAILURE);  
  91.         }  
  92.     }  
  93.     close(sockfd);  
  94.     return 0;  
  95. }  
接收端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <netinet/in.h>  
  6. #include <arpa/inet.h>  
  7. #include <unistd.h>  
  8. #include <stdlib.h>  
  9. #include <errno.h>  
  10. #define  BUFSIZE 128  
  11.   
  12. int main(int argc,char *argv[])  
  13. {  
  14.     int server_sockfd, client_sockfd;  
  15.     int server_len, client_len;  
  16.     struct sockaddr_in server_address;  
  17.     struct sockaddr_in client_address;  
  18.     int i,byte;  
  19.     char char_send[BUFSIZE];  
  20.   
  21.     server_sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  22.     server_address.sin_family = AF_INET;  
  23.     if (inet_aton(argv[1], (struct in_addr *) & server_address.sin_addr.s_addr) == 0)  
  24.     {  
  25.         perror(argv[1]);  
  26.         exit(EXIT_FAILURE);  
  27.     }  
  28.     server_address.sin_port = htons(7838);  
  29.     server_len = sizeof(server_address);  
  30.   
  31.     bind(server_sockfd, (struct sockaddr *)&server_address, server_len);  
  32.     listen(server_sockfd, 5);  
  33.     printf("server waiting for connect\n");  
  34.   
  35.     client_len = sizeof(client_address);  
  36.     client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);  
  37.   
  38.     for(i=0;i<5;i++)  
  39.     {  
  40.         memset(char_send,'\0',BUFSIZE);  
  41.         printf("input message to send:");  
  42.         fgets(char_send,BUFSIZE,stdin);  
  43.   
  44.         if((byte=send(client_sockfd,char_send,strlen(char_send),0))==-1)  
  45.         {  
  46.             perror("send");  
  47.             exit(EXIT_FAILURE);  
  48.         }  
  49.         memset(char_send,'\0',BUFSIZE);  
  50.         byte = recv(client_sockfd, char_send, BUFSIZE,MSG_DONTWAIT);  
  51.   
  52.         if(byte > 0)  
  53.         {  
  54.             printf("get %d message:%s", byte, char_send);  
  55.             byte=0;  
  56.         }  
  57.         else if(byte<0)  
  58.         {  
  59.             if(errno==EAGAIN)  
  60.             {  
  61.                 errno=0;  
  62.                 continue;  
  63.             }  
  64.             else  
  65.             {  
  66.                 perror("recv");  
  67.                 exit(EXIT_FAILURE);  
  68.             }  
  69.         }  
  70.     }     
  71.     shutdown(client_sockfd,2);  
  72.     shutdown(server_sockfd,2);  
  73. }  
发送端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_unblock_server 172.18.229.62  
  2. server waiting for connect  
  3. input message to send:hello  
  4. input message to send:test  
  5. get 3 message:hi  
  6. input message to send:go  
  7. input message to send:read  
  8. input message to send:why  
接收端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_unblock_client 172.18.229.62 172.18.229.62  
  2. get 6 message:hello  
  3. input message to send:hi  
  4. get 5 message:test  
  5. input message to send:go  
  6. get 12 message:go  
  7. read  
  8. why  
  9. input message to send:hi  
socket多路复用应用

select函数

select提供轮循等待的方式从多个文件描述符中获取状态发变后的消息 。


第1个参数指定要检测的文件描述符的范围。测试范围在0到nfds−1之间的文件描述符(nfds=这些文件描述符中的最大值+1)。
第2、3、4三个参数类型都是fd_set *。这三个参数都是文件描述符的集合。
dfds包含所有因状态变成可读而触发select()函数返回的文件描述符;
wtfds包含所有因状态变成可写而触发select()函数返回的文件描述符;
exfds包含所有因状态发生特殊异常(例如带外数据到来)而触发select()函数返回的文件描述符 

文件描述符集合操作 

最后一个参数timeout显然是一个超时时限,其类型是struct timeval * 。


如果函数执行错误,将返回-1;
如果因超时而返回,即在timeout所描述的时间范围内没有任何描述符出现异常,则返回0;
如果因一个或多个文件描述符异常而返回,其返回值为产生异常的文件描述符数,并在相应文件描述符集合中清除未产生异常的文件描述符记录,因此,返回后可以根据文件描述符集合的记录查找出是哪一个文件描述符返回。

基本示例

检测某个socket是否有数据可读


pselect函数


poll与ppoll函数

poll函数

poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <poll.h>  
  2. int poll(struct pollfd *fd, nfds_t nfds, int timeout);  
    参数:
   1)第一个参数:一个结构数组,struct pollfd结构如下:
[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. struct pollfd{  
  2. int fd;              //文件描述符  
  3. short events;    //请求的事件  
  4. short revents;   //返回的事件  
  5. };  
  events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件,poll用已经发生的事件填充revents。poll函数通过在revents中设置标志肌肤POLLHUP、POLLERR和POLLNVAL来反映相关条件的存在。不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUN或返回0字节的常规读操作来传达。即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作。
poll函数的事件标志符值
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
  注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
  2)第二个参数nfds:要监视的描述符的数目。
  3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。
timeout值 说明
INFTIM 永远等待
0 立即返回,不阻塞进程
>0 等待指定数目的毫秒数

ppoll函数

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <poll.h>  
  2. int ppoll(struct pollfd *fd, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);  

与pselect一样,ppoll函数可以在阻塞过程中屏蔽某些信号,而在timeout时间上,ppoll的时间精度更高。

多路复用应用示例

服务器代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <stdlib.h>  
  4.   
  5. #include <errno.h>  
  6.   
  7. #include <string.h>  
  8.   
  9. #include <sys/types.h>  
  10.   
  11. #include <netinet/in.h>  
  12.   
  13. #include <sys/socket.h>  
  14.   
  15. #include <sys/wait.h>  
  16.   
  17. #include <unistd.h>  
  18.   
  19. #include <arpa/inet.h>  
  20.   
  21. #include <sys/time.h>  
  22.   
  23. #include <sys/types.h>  
  24.   
  25.   
  26.   
  27. #define MAXBUF 1024  
  28.   
  29.   
  30.   
  31. int main(int argc, char **argv)  
  32.   
  33. {  
  34.   
  35.         int sockfd, new_fd;  
  36.   
  37.         socklen_t len;  
  38.   
  39.         struct sockaddr_in my_addr, their_addr;  
  40.   
  41.         unsigned int myport, lisnum;  
  42.   
  43.         char buf[MAXBUF + 1];  
  44.   
  45.         fd_set rfds;  
  46.   
  47.         struct timeval tv;  
  48.   
  49.         int retval, maxfd = -1;  
  50.   
  51.   
  52.   
  53.         if (argv[2])  
  54.   
  55.                 myport = atoi(argv[2]);  
  56.   
  57.         else  
  58.   
  59.                 myport = 7838;  
  60.   
  61.         if (argv[3])  
  62.   
  63.                 lisnum = atoi(argv[3]);  
  64.   
  65.         else  
  66.   
  67.                 lisnum = 2;  
  68.   
  69.         if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {  
  70.   
  71.                 perror("socket");  
  72.   
  73.                 exit(EXIT_FAILURE);  
  74.   
  75.         }  
  76.   
  77.   
  78.   
  79.         bzero(&my_addr, sizeof(my_addr));  
  80.   
  81.         my_addr.sin_family = PF_INET;  
  82.   
  83.         my_addr.sin_port = htons(myport);  
  84.   
  85.         if (argv[1])  
  86.   
  87.             my_addr.sin_addr.s_addr = inet_addr(argv[1]);  
  88.   
  89.         else  
  90.   
  91.             my_addr.sin_addr.s_addr = INADDR_ANY;  
  92.   
  93.         if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {  
  94.   
  95.            perror("bind");  
  96.   
  97.            exit(EXIT_FAILURE);  
  98.   
  99.         }  
  100.   
  101.          if (listen(sockfd, lisnum) == -1) {  
  102.   
  103.             perror("listen");  
  104.   
  105.             exit(EXIT_FAILURE);  
  106.   
  107.          }  
  108.   
  109.   
  110.   
  111.          while (1)   
  112.   
  113.          {  
  114.   
  115.             printf ("\n----wait for new connect\n");  
  116.   
  117.             len = sizeof(struct sockaddr);  
  118.   
  119.             if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1) {  
  120.   
  121.                 perror("accept");  
  122.   
  123.                 exit(errno);  
  124.   
  125.             } else  
  126.   
  127.                 printf("server: got connection from %s, port %d, socket %d\n",   
  128.   
  129.                         inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);  
  130.   
  131.             while (1)   
  132.   
  133.             {  
  134.   
  135.                 FD_ZERO(&rfds);  
  136.   
  137.                 FD_SET(0, &rfds);  
  138.   
  139.                 FD_SET(new_fd, &rfds);  
  140.   
  141.                 maxfd = new_fd;  
  142.   
  143.                 tv.tv_sec = 1;  
  144.   
  145.                 tv.tv_usec = 0;  
  146.   
  147.                 retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  148.   
  149.                 if (retval == -1)   
  150.   
  151.                 {  
  152.   
  153.                     perror("select");  
  154.   
  155.                     exit(EXIT_FAILURE);  
  156.   
  157.                 } else if (retval == 0) {  
  158.   
  159.                         continue;  
  160.   
  161.                 }   
  162.   
  163.                 else  
  164.   
  165.                 {  
  166.   
  167.                     if (FD_ISSET(0, &rfds))  
  168.   
  169.                     {  
  170.   
  171.                             bzero(buf, MAXBUF + 1);  
  172.   
  173.                             fgets(buf, MAXBUF, stdin);  
  174.   
  175.                             if (!strncasecmp(buf, "quit", 4)) {  
  176.   
  177.                                 printf("i will quit!\n");  
  178.   
  179.                                 break;  
  180.   
  181.                             }  
  182.   
  183.                             len = send(new_fd, buf, strlen(buf) - 1, 0);  
  184.   
  185.                             if (len > 0)  
  186.   
  187.                                 printf ("send successful,%d byte send!\n",len);  
  188.   
  189.                             else {  
  190.   
  191.                                 printf("send failure!");  
  192.   
  193.                                 break;  
  194.   
  195.                             }  
  196.   
  197.                     }  
  198.   
  199.                     if (FD_ISSET(new_fd, &rfds))   
  200.   
  201.                     {   
  202.   
  203.                             bzero(buf, MAXBUF + 1);  
  204.   
  205.                             len = recv(new_fd, buf, MAXBUF, 0);  
  206.   
  207.                             if (len > 0)  
  208.   
  209.                                 printf ("recv success :'%s',%dbyte recv\n", buf, len);  
  210.   
  211.                             else  
  212.   
  213.                             {  
  214.   
  215.                                 if (len < 0)  
  216.   
  217.                                     printf("recv failure\n");  
  218.   
  219.                                 else  
  220.   
  221.                                 {  
  222.   
  223.                                     printf("the ohter one end ,quit\n");  
  224.   
  225.                                     break;  
  226.   
  227.                                 }  
  228.   
  229.                             }  
  230.   
  231.                     }  
  232.   
  233.                  }  
  234.   
  235.             }  
  236.   
  237.             close(new_fd);  
  238.   
  239.             printf("need othe connecdt (no->quit)");  
  240.   
  241.             fflush(stdout);  
  242.   
  243.             bzero(buf, MAXBUF + 1);  
  244.   
  245.             fgets(buf, MAXBUF, stdin);  
  246.   
  247.             if (!strncasecmp(buf, "no", 2))   
  248.   
  249.             {  
  250.   
  251.                 printf("quit!\n");  
  252.   
  253.                 break;  
  254.   
  255.             }  
  256.   
  257.         }  
  258.   
  259.         close(sockfd);  
  260.   
  261.         return 0;  
  262.   
  263. }  

客户端代码

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. #include <string.h>  
  4.   
  5. #include <errno.h>  
  6.   
  7. #include <sys/socket.h>  
  8.   
  9. #include <resolv.h>  
  10.   
  11. #include <stdlib.h>  
  12.   
  13. #include <netinet/in.h>  
  14.   
  15. #include <arpa/inet.h>  
  16.   
  17. #include <unistd.h>  
  18.   
  19. #include <sys/time.h>  
  20.   
  21. #include <sys/types.h>  
  22.   
  23.   
  24.   
  25. #define MAXBUF 1024  
  26.   
  27. int main(int argc, char **argv)  
  28.   
  29. {  
  30.   
  31.     int sockfd, len;  
  32.   
  33.     struct sockaddr_in dest;  
  34.   
  35.     char buffer[MAXBUF + 1];  
  36.   
  37.     fd_set rfds;  
  38.   
  39.     struct timeval tv;  
  40.   
  41.     int retval, maxfd = -1;  
  42.   
  43.   
  44.   
  45.     if (argc != 3)   
  46.   
  47.     {  
  48.   
  49.         printf("argv format errno,pls:\n\t\t%s IP port\n",argv[0], argv[0]);  
  50.   
  51.         exit(EXIT_FAILURE);  
  52.   
  53.     }  
  54.   
  55.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  56.   
  57.     {  
  58.   
  59.         perror("Socket");  
  60.   
  61.         exit(EXIT_FAILURE);  
  62.   
  63.     }  
  64.   
  65.   
  66.   
  67.     bzero(&dest, sizeof(dest));  
  68.   
  69.     dest.sin_family = AF_INET;  
  70.   
  71.     dest.sin_port = htons(atoi(argv[2]));  
  72.   
  73.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)   
  74.   
  75.     {  
  76.   
  77.         perror(argv[1]);  
  78.   
  79.         exit(EXIT_FAILURE);  
  80.   
  81.     }  
  82.   
  83.   
  84.   
  85.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)   
  86.   
  87.     {  
  88.   
  89.         perror("Connect ");  
  90.   
  91.         exit(EXIT_FAILURE);  
  92.   
  93.     }  
  94.   
  95.   
  96.   
  97.     printf("\nget ready pls chat\n");  
  98.   
  99.     while (1)   
  100.   
  101.     {  
  102.   
  103.         FD_ZERO(&rfds);  
  104.   
  105.         FD_SET(0, &rfds);  
  106.   
  107.         FD_SET(sockfd, &rfds);  
  108.   
  109.         maxfd = sockfd;  
  110.   
  111.         tv.tv_sec = 1;  
  112.   
  113.         tv.tv_usec = 0;  
  114.   
  115.         retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  116.   
  117.         if (retval == -1)   
  118.   
  119.         {  
  120.   
  121.             printf("select %s", strerror(errno));  
  122.   
  123.             break;  
  124.   
  125.         }   
  126.   
  127.         else if (retval == 0)  
  128.   
  129.             continue;  
  130.   
  131.         else  
  132.   
  133.         {  
  134.   
  135.             if (FD_ISSET(sockfd, &rfds))   
  136.   
  137.             {  
  138.   
  139.                 bzero(buffer, MAXBUF + 1);  
  140.   
  141.                 len = recv(sockfd, buffer, MAXBUF, 0);  
  142.   
  143.                 if (len > 0)  
  144.   
  145.                     printf ("recv message:'%s',%d byte recv\n",buffer, len);  
  146.   
  147.                 else   
  148.   
  149.                 {  
  150.   
  151.                     if (len < 0)  
  152.   
  153.                         printf ("message recv failure\n");  
  154.   
  155.                     else  
  156.   
  157.                     {  
  158.   
  159.                         printf("the othe quit ,quit\n");  
  160.   
  161.                         break;  
  162.   
  163.                     }  
  164.   
  165.                 }  
  166.   
  167.             }  
  168.   
  169.             if (FD_ISSET(0, &rfds))   
  170.   
  171.             {  
  172.   
  173.                 bzero(buffer, MAXBUF + 1);  
  174.   
  175.                 fgets(buffer, MAXBUF, stdin);  
  176.   
  177.                 if (!strncasecmp(buffer, "quit", 4)) {  
  178.   
  179.                     printf("i will quit\n");  
  180.   
  181.                     break;  
  182.   
  183.                 }  
  184.   
  185.                 len = send(sockfd, buffer, strlen(buffer) - 1, 0);  
  186.   
  187.                 if (len < 0) {  
  188.   
  189.                     printf ("message send failure");  
  190.   
  191.                     break;  
  192.   
  193.                 } else  
  194.   
  195.                     printf  
  196.   
  197.                         ("send success,%d byte send\n",len);  
  198.   
  199.             }  
  200.   
  201.         }  
  202.   
  203.     }  
  204.   
  205.     close(sockfd);  
  206.   
  207.     return 0;  
  208.   
  209. }   
服务器运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_sy_chat_server 172.18.229.62 8000  
  2.   
  3. ----wait for new connect  
  4. server: got connection from 172.18.229.62, port 55410, socket 4  
  5. recv success :'hello',5byte recv  
  6. recv success :'test',4byte recv  
  7. recv success :'why',3byte recv  
  8. ready  
  9. send successful,5 byte send!  
  10. end  
  11. send successful,3 byte send!  
  12. quit  
  13. i will quit!  
  14. need othe connecdt (no->quit)no  
  15. quit!  
客户端运行结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. $ ./tcp_sy_chat_client 172.18.229.62 8000  
  2.   
  3. get ready pls chat  
  4. hello  
  5. send success,5 byte send  
  6. test  
  7. send success,4 byte send  
  8. why  
  9. send success,3 byte send  
  10. recv message:'ready',5 byte recv  
  11. recv message:'end',3 byte recv  
  12. the othe quit ,quit  

原文链接

http://blog.csdn.net/geng823/article/details/41750405

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值