原文:http://blog.csdn.net/yfkiss/article/details/7516589

IO模型在Richard Stevens的《UNIX网络编程,第一卷》(程序猿必备!)一书中有非常详尽的描述,以下简要介绍,并给出代码示例。

另外比较好的总结性blog,推荐:
使用异步 I/O 大大提高应用程序的性能
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)

常见网络IO模型:阻塞式IO、无阻塞式IO、IO复用、异步IO、信号驱动

阻塞式IO:
在一个进程发出IO请求后,进入阻塞状态,直到内核返回数据,才重新运行,如图:
网络编程--IO模型示例
代码
sever端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netinet/in.h>
  6. #include<sys/socket.h>
  7. #include<unistd.h>
  8. intmain()
  9. {
  10. intsockfd,new_fd;
  11. intsin_size,numbytes;
  12. structsockaddr_inaddr,cliaddr;
  13. //创建socket
  14. if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  15. {
  16. perror("createSocket");
  17. return-1;
  18. }
  19. //初始化socket结构
  20. memset(&addr,0,sizeof(addr));
  21. addr.sin_family=AF_INET;
  22. addr.sin_port=htons(7092);
  23. addr.sin_addr.s_addr=htonl(INADDR_ANY);
  24. //绑定套接口
  25. if(bind(sockfd,(structsockaddr*)&addr,sizeof(structsockaddr))==-1)
  26. {
  27. perror("bind");
  28. return-1;
  29. }
  30. //创建监听套接口
  31. if(listen(sockfd,10)==-1)
  32. {
  33. perror("listen");
  34. return-1;
  35. }
  36. printf("serverisrunning!\n");
  37. charbuff[1024];
  38. //等待连接
  39. while(1)
  40. {
  41. sin_size=sizeof(structsockaddr_in);
  42. //接受连接
  43. if((new_fd=accept(sockfd,(structsockaddr*)&cliaddr,(socklen_t*)&sin_size))==-1)
  44. {
  45. perror("accept");
  46. return-1;
  47. }
  48. //生成一个子进程来完成和客户端的会话,父进程继续监听
  49. if(!fork())
  50. {
  51. //读取客户端发来的信息
  52. memset(buff,0,sizeof(buff));
  53. if((numbytes=recv(new_fd,buff,sizeof(buff),0))==-1)
  54. {
  55. perror("recv");
  56. return-1;
  57. }
  58. printf("buff=%s\n",buff);
  59. //将从客户端接收到的信息再发回客户端
  60. if(send(new_fd,buff,strlen(buff),0)==-1)
  61. {
  62. perror("send");
  63. }
  64. close(new_fd);
  65. return0;
  66. }
  67. //父进程关闭new_fd
  68. close(new_fd);
  69. }
  70. close(sockfd);
  71. }
client端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netdb.h>
  6. #include<sys/types.h>
  7. #include<netinet/in.h>
  8. #include<sys/socket.h>
  9. #include<unistd.h>
  10. intmain(intargc,char*argv[])
  11. {
  12. if(argc!=3)
  13. {
  14. printf("%s:inputIP&port\n",argv[0]);
  15. return1;
  16. }
  17. intsockfd,numbytes;
  18. charbuf[100]="helloworld";
  19. structhostent*he;
  20. structsockaddr_intheir_addr;
  21. //将基本名字和地址转换
  22. he=gethostbyname(argv[1]);
  23. //建立一个TCP套接口
  24. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  25. {
  26. perror("socket");
  27. exit(1);
  28. }
  29. //初始化结构体
  30. their_addr.sin_family=AF_INET;
  31. their_addr.sin_port=htons(atoi(argv[2]));
  32. their_addr.sin_addr=*((structin_addr*)he->h_addr);
  33. bzero(&(their_addr.sin_zero),8);
  34. //和服务器建立连接
  35. if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1)
  36. {
  37. perror("connect");
  38. exit(1);
  39. }
  40. //向服务器发送字符串
  41. if(send(sockfd,buf,strlen(buf),0)==-1)
  42. {
  43. perror("send");
  44. exit(1);
  45. }
  46. memset(buf,0,sizeof(buf));
  47. //接受从服务器返回的信息
  48. if((numbytes=recv(sockfd,buf,100,0))==-1)
  49. {
  50. perror("recv");
  51. exit(1);
  52. }
  53. close(sockfd);
  54. return0;
  55. }

运行:
$ ./bin/server
server is running!
buff=hello world
buff=hello world

$ ./bin/client 10.32.49.10 7092
$ ./bin/client 10.32.49.10 7092

无阻塞式IO:
在一个进程发出IO请求后,不阻塞,如果数据没有准备好,就直接返回错误码,如图:
网络编程--IO模型示例
可以通过fcntl控制socket描述符属性。
int flags;
flag=fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flag|O_NONBLOCK)

非阻塞式I/O模型对4种I/O操作返回的错误
读操作:接收缓冲区无数据时返回EWOULDBLOCK
写操作:发送缓冲区无空间时返回EWOULDBLOCK;空间不够时部分拷贝,返回实际拷贝字节数
建立连接:启动3次握手,立刻返回错误EINPROGRESS;服务器客户端在同一主机上connect立即返回成功
接受连接:没有新连接返回EWOULDBLOCK

代码:
server端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netinet/in.h>
  6. #include<sys/socket.h>
  7. #include<unistd.h>
  8. #include<fcntl.h>
  9. intmain()
  10. {
  11. intsockfd,new_fd;
  12. intsin_size;
  13. structsockaddr_inaddr,cliaddr;
  14. //创建socket
  15. if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  16. {
  17. perror("createSocket");
  18. return-1;
  19. }
  20. //初始化socket结构
  21. memset(&addr,0,sizeof(addr));
  22. addr.sin_family=AF_INET;
  23. addr.sin_port=htons(7092);
  24. addr.sin_addr.s_addr=htonl(INADDR_ANY);
  25. //绑定套接口
  26. if(bind(sockfd,(structsockaddr*)&addr,sizeof(structsockaddr))==-1)
  27. {
  28. perror("bind");
  29. return-1;
  30. }
  31. //创建监听套接口
  32. if(listen(sockfd,10)==-1)
  33. {
  34. perror("listen");
  35. return-1;
  36. }
  37. printf("serverisrunning!\n");
  38. charbuff[1024];
  39. //等待连接
  40. while(1)
  41. {
  42. sin_size=sizeof(structsockaddr_in);
  43. //接受连接
  44. if((new_fd=accept(sockfd,(structsockaddr*)&cliaddr,(socklen_t*)&sin_size))==-1)
  45. {
  46. perror("accept");
  47. return-1;
  48. }
  49. //生成一个子进程来完成和客户端的会话,父进程继续监听
  50. if(!fork())
  51. {
  52. //设置new_fd无阻塞属性
  53. intflags;
  54. if((flags=fcntl(new_fd,F_GETFL,0))<0)
  55. {
  56. perror("fcntlF_GETFL");
  57. }
  58. flags|=O_NONBLOCK;
  59. if(fcntl(new_fd,F_SETFL,flags)<0)
  60. {
  61. perror("fcntlF_SETFL");
  62. }
  63. //读取客户端发来的信息
  64. memset(buff,0,sizeof(buff));
  65. while(1)
  66. {
  67. if((recv(new_fd,buff,sizeof(buff),0))<0)
  68. {
  69. if(errno==EWOULDBLOCK)
  70. {
  71. perror("recverror,wait....");
  72. sleep(1);
  73. continue;
  74. }
  75. }
  76. else
  77. {
  78. printf("buff=%s\n",buff);
  79. }
  80. break;
  81. }
  82. //发送数据
  83. while(1)
  84. {
  85. if(send(new_fd,buff,strlen(buff),0)<0)
  86. {
  87. if(errno==EWOULDBLOCK)
  88. {
  89. perror("senderror,wait....");
  90. sleep(1);
  91. continue;
  92. }
  93. }
  94. else
  95. {
  96. printf("buff=%s\n",buff);
  97. }
  98. break;
  99. }
  100. close(new_fd);
  101. return0;
  102. }
  103. //父进程关闭new_fd
  104. close(new_fd);
  105. }
  106. close(sockfd);
  107. }

client端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netdb.h>
  6. #include<sys/types.h>
  7. #include<netinet/in.h>
  8. #include<sys/socket.h>
  9. #include<unistd.h>
  10. intmain(intargc,char*argv[])
  11. {
  12. if(argc!=3)
  13. {
  14. printf("%s:inputIP&port\n",argv[0]);
  15. return1;
  16. }
  17. intsockfd,numbytes;
  18. charbuf[100]="helloworld";
  19. structhostent*he;
  20. structsockaddr_intheir_addr;
  21. //将基本名字和地址转换
  22. he=gethostbyname(argv[1]);
  23. //建立一个TCP套接口
  24. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  25. {
  26. perror("socket");
  27. exit(1);
  28. }
  29. //初始化结构体
  30. their_addr.sin_family=AF_INET;
  31. their_addr.sin_port=htons(atoi(argv[2]));
  32. their_addr.sin_addr=*((structin_addr*)he->h_addr);
  33. bzero(&(their_addr.sin_zero),8);
  34. //和服务器建立连接
  35. if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1)
  36. {
  37. perror("connect");
  38. exit(1);
  39. }
  40. sleep(5);
  41. //向服务器发送字符串
  42. if(send(sockfd,buf,strlen(buf),0)==-1)
  43. {
  44. perror("send");
  45. exit(1);
  46. }
  47. memset(buf,0,sizeof(buf));
  48. sleep(5);
  49. //接受从服务器返回的信息
  50. if((numbytes=recv(sockfd,buf,100,0))==-1)
  51. {
  52. perror("recv");
  53. exit(1);
  54. }
  55. close(sockfd);
  56. return0;
  57. }

运行:
$ ./bin/server
server is running!
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
buff=hello world
buff=hello world

$ ./bin/client 10.32.49.10 7092

IO复用:
IO复用阻塞在select、poll或epoll这样的系统调用上,通过这种方式,在不使用多线程的前提下,单个进程可以同时处理多个网络连接的IO。如图:
网络编程--IO模型示例
代码
sever端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netinet/in.h>
  6. #include<sys/socket.h>
  7. #include<unistd.h>
  8. #include<fcntl.h>
  9. #include<netdb.h>
  10. #include<sys/epoll.h>
  11. #defineMAXEVENT1024
  12. intcreate_server_socket(int&sockfd)
  13. {
  14. structsockaddr_inaddr;
  15. //创建socket
  16. if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  17. {
  18. perror("createSocket");
  19. return-1;
  20. }
  21. //初始化socket结构
  22. memset(&addr,0,sizeof(addr));
  23. addr.sin_family=AF_INET;
  24. addr.sin_port=htons(7092);
  25. addr.sin_addr.s_addr=htonl(INADDR_ANY);
  26. //绑定套接口
  27. if(bind(sockfd,(structsockaddr*)&addr,sizeof(structsockaddr))==-1)
  28. {
  29. perror("bind");
  30. return-1;
  31. }
  32. //创建监听套接口
  33. if(listen(sockfd,10)==-1)
  34. {
  35. perror("listen");
  36. return-1;
  37. }
  38. return0;
  39. }
  40. intset_socket_non_blocking(intfd)
  41. {
  42. intflags,s;
  43. flags=fcntl(fd,F_GETFL,0);
  44. if(flags==-1)
  45. {
  46. perror("fcntlF_GETFLfailed");
  47. return-1;
  48. }
  49. flags|=O_NONBLOCK;
  50. s=fcntl(fd,F_SETFL,flags);
  51. if(s==-1)
  52. {
  53. perror("fcntlF_SETFLfailed");
  54. return-1;
  55. }
  56. return0;
  57. }
  58. intmain()
  59. {
  60. intsockfd,efd;
  61. structepoll_eventevent;
  62. structepoll_event*events;
  63. ints;
  64. if(create_server_socket(sockfd)!=0)
  65. {
  66. perror("createserversockfailed\n");
  67. return1;
  68. }
  69. set_socket_non_blocking(sockfd);
  70. printf("serverisrunning!\n");
  71. //创建一个epoll的句柄
  72. //intepoll_create(intsize)
  73. //SinceLinux2.6.8,thesizeargumentisunused.(Thekerneldynamicallysizestherequireddatastructureswithoutneedingthisinitialhint.)
  74. efd=epoll_create(MAXEVENT);
  75. if(efd==-1)
  76. {
  77. perror("epoll_create");
  78. abort();
  79. }
  80. //注册新事件到epollefd
  81. event.data.fd=sockfd;
  82. event.events=EPOLLIN|EPOLLET;
  83. s=epoll_ctl(efd,EPOLL_CTL_ADD,sockfd,&event);
  84. if(s==-1)
  85. {
  86. perror("epoll_ctlEPOLL_CTL_ADDfailed");
  87. abort();
  88. }
  89. events=(epoll_event*)calloc(MAXEVENT,sizeof(event));
  90. while(1)
  91. {
  92. intn,i;
  93. n=epoll_wait(efd,events,MAXEVENT,-1);
  94. for(i=0;i<n;i++)
  95. {
  96. //fderror
  97. if((events[i].events&EPOLLERR)||
  98. (events[i].events&EPOLLHUP)||
  99. (!(events[i].events&EPOLLIN)))
  100. {
  101. perror("epollerror\n");
  102. close(events[i].data.fd);
  103. continue;
  104. }
  105. //新连接
  106. elseif(sockfd==events[i].data.fd)
  107. {
  108. while(1)
  109. {
  110. structsockaddrin_addr;
  111. socklen_tin_len;
  112. intinfd;
  113. charhbuf[NI_MAXHOST],sbuf[NI_MAXSERV];
  114. //接受连接
  115. in_len=sizeof(in_addr);
  116. infd=accept(sockfd,&in_addr,&in_len);
  117. if(infd==-1)
  118. {
  119. if((errno==EAGAIN)||
  120. (errno==EWOULDBLOCK))
  121. {
  122. //已接受所有连接
  123. break;
  124. }
  125. else
  126. {
  127. perror("accept");
  128. break;
  129. }
  130. }
  131. s=getnameinfo(&in_addr,in_len,
  132. hbuf,sizeofhbuf,
  133. sbuf,sizeofsbuf,
  134. NI_NUMERICHOST|NI_NUMERICSERV);
  135. if(s==0)
  136. {
  137. printf("Acceptedconnectionondescriptor%d"
  138. "(host=%s,port=%s)\n",infd,hbuf,sbuf);
  139. }
  140. /*设置新接受的socket连接无阻塞*/
  141. s=set_socket_non_blocking(infd);
  142. if(s==-1)
  143. {
  144. return1;
  145. }
  146. //注册新事件到epoll
  147. event.data.fd=infd;
  148. event.events=EPOLLIN|EPOLLET;
  149. s=epoll_ctl(efd,EPOLL_CTL_ADD,infd,&event);
  150. if(s==-1)
  151. {
  152. perror("epoll_ctl");
  153. return1;
  154. }
  155. }
  156. continue;
  157. }
  158. //数据可读
  159. else
  160. {
  161. intdone=0;
  162. while(1)
  163. {
  164. ssize_tcount;
  165. charbuf[512];
  166. count=read(events[i].data.fd,buf,sizeof(buf));
  167. if(count==-1)
  168. {
  169. //数据读完
  170. if(errno!=EAGAIN)
  171. {
  172. perror("read");
  173. done=1;
  174. }
  175. break;
  176. }
  177. elseif(count==0)
  178. {
  179. /*Endoffile.Theremotehasclosedthe
  180. connection.*/
  181. done=1;
  182. break;
  183. }
  184. printf("recv:%s\n",buf);
  185. }
  186. if(done)
  187. {
  188. printf("Closedconnectionondescriptor%d\n",events[i].data.fd);
  189. close(events[i].data.fd);
  190. }
  191. }
  192. }
  193. }
  194. free(events);
  195. close(sockfd);
  196. return0;
  197. }
client端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netdb.h>
  6. #include<sys/types.h>
  7. #include<netinet/in.h>
  8. #include<sys/socket.h>
  9. #include<unistd.h>
  10. intmain(intargc,char*argv[])
  11. {
  12. if(argc!=3)
  13. {
  14. printf("%s:inputIP&port\n",argv[0]);
  15. return1;
  16. }
  17. intsockfd,numbytes;
  18. charbuf[100]="helloworld";
  19. structhostent*he;
  20. structsockaddr_intheir_addr;
  21. //将基本名字和地址转换
  22. he=gethostbyname(argv[1]);
  23. //建立一个TCP套接口
  24. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  25. {
  26. perror("socket");
  27. exit(1);
  28. }
  29. //初始化结构体
  30. their_addr.sin_family=AF_INET;
  31. their_addr.sin_port=htons(atoi(argv[2]));
  32. their_addr.sin_addr=*((structin_addr*)he->h_addr);
  33. bzero(&(their_addr.sin_zero),8);
  34. //和服务器建立连接
  35. if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1)
  36. {
  37. perror("connect");
  38. exit(1);
  39. }
  40. //向服务器发送字符串
  41. while(1)
  42. {
  43. if(send(sockfd,buf,strlen(buf),0)==-1)
  44. {
  45. perror("send");
  46. exit(1);
  47. }
  48. sleep(2);
  49. }
  50. memset(buf,0,sizeof(buf));
  51. close(sockfd);
  52. return0;
  53. }

运行:
$ ./bin/server
server is running!
Accepted connection on descriptor 5 (host=10.32.49.10, port=39001)
recv: hello world
recv: hello world
recv: hello world
recv: hello world

./bin/client 10.32.49.10 7092

异步IO:
在一个进程发出IO请求后直接返回,内核在整个操作(包括将数据复制到进程缓冲区)完成后通知进程,如图:
网络编程--IO模型示例
代码
server端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netinet/in.h>
  6. #include<sys/socket.h>
  7. #include<unistd.h>
  8. #include<fcntl.h>
  9. #include<aio.h>
  10. #include<pthread.h>
  11. #defineBUF_SIZE1024
  12. voidaio_completion_handler(sigval_tsigval);
  13. voidsetup_io(intfd,aiocb&my_aiocb)
  14. {
  15. //初始化AIO请求
  16. bzero((char*)&my_aiocb,sizeof(structaiocb));
  17. my_aiocb.aio_fildes=fd;
  18. my_aiocb.aio_buf=malloc(BUF_SIZE+1);
  19. my_aiocb.aio_nbytes=BUF_SIZE;
  20. my_aiocb.aio_offset=0;
  21. //设置线程回调函数
  22. my_aiocb.aio_sigevent.sigev_notify=SIGEV_THREAD;
  23. my_aiocb.aio_sigevent.sigev_notify_function=aio_completion_handler;
  24. my_aiocb.aio_sigevent.sigev_notify_attributes=NULL;
  25. my_aiocb.aio_sigevent.sigev_value.sival_ptr=&my_aiocb;
  26. }
  27. //回调函数
  28. voidaio_completion_handler(sigval_tsigval)
  29. {
  30. structaiocb*req;
  31. intret;
  32. req=(structaiocb*)sigval.sival_ptr;
  33. if(aio_error(req)==0)
  34. {
  35. if((ret=aio_return(req))>0)
  36. {
  37. printf("Threadid%urecv:%s\n",(unsignedint)pthread_self(),(char*)req->aio_buf);
  38. }
  39. }
  40. char*buf=(char*)req->aio_buf;
  41. if(send(req->aio_fildes,buf,strlen(buf),0)==-1)
  42. {
  43. perror("send");
  44. return;
  45. }
  46. close(req->aio_fildes);
  47. return;
  48. }
  49. intmain()
  50. {
  51. intsockfd;
  52. intsin_size;
  53. structsockaddr_inaddr,cliaddr;
  54. //创建socket
  55. if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  56. {
  57. perror("createSocket");
  58. return-1;
  59. }
  60. //初始化socket结构
  61. memset(&addr,0,sizeof(addr));
  62. addr.sin_family=AF_INET;
  63. addr.sin_port=htons(7092);
  64. addr.sin_addr.s_addr=htonl(INADDR_ANY);
  65. //绑定套接口
  66. if(bind(sockfd,(structsockaddr*)&addr,sizeof(structsockaddr))==-1)
  67. {
  68. perror("bind");
  69. return-1;
  70. }
  71. //创建监听套接口
  72. if(listen(sockfd,10)==-1)
  73. {
  74. perror("listen");
  75. return-1;
  76. }
  77. printf("serverisrunning!\n");
  78. //等待连接
  79. while(1)
  80. {
  81. intnew_fd;
  82. structaiocbmy_aiocb;
  83. sin_size=sizeof(structsockaddr_in);
  84. //接受连接
  85. if((new_fd=accept(sockfd,(structsockaddr*)&cliaddr,(socklen_t*)&sin_size))==-1)
  86. {
  87. perror("accept");
  88. return-1;
  89. }
  90. printf("Threadid%uacceptconnect,fd:%d\n",(unsignedint)pthread_self(),new_fd);
  91. setup_io(new_fd,my_aiocb);
  92. aio_read(&my_aiocb);
  93. }
  94. close(sockfd);
  95. }

client端:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<errno.h>
  4. #include<string.h>
  5. #include<netdb.h>
  6. #include<sys/types.h>
  7. #include<netinet/in.h>
  8. #include<sys/socket.h>
  9. #include<unistd.h>
  10. intmain(intargc,char*argv[])
  11. {
  12. if(argc!=3)
  13. {
  14. printf("%s:inputIP&port\n",argv[0]);
  15. return1;
  16. }
  17. intsockfd,numbytes;
  18. charbuf[100]="helloworld";
  19. structhostent*he;
  20. structsockaddr_intheir_addr;
  21. //将基本名字和地址转换
  22. he=gethostbyname(argv[1]);
  23. //建立一个TCP套接口
  24. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  25. {
  26. perror("socket");
  27. exit(1);
  28. }
  29. //初始化结构体
  30. their_addr.sin_family=AF_INET;
  31. their_addr.sin_port=htons(atoi(argv[2]));
  32. their_addr.sin_addr=*((structin_addr*)he->h_addr);
  33. bzero(&(their_addr.sin_zero),8);
  34. //和服务器建立连接
  35. if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1)
  36. {
  37. perror("connect");
  38. exit(1);
  39. }
  40. //向服务器发送字符串
  41. if(send(sockfd,buf,strlen(buf),0)==-1)
  42. {
  43. perror("send");
  44. exit(1);
  45. }
  46. //接收数据
  47. if((numbytes=recv(sockfd,buf,100,0))==-1)
  48. {
  49. perror("recv");
  50. return1;
  51. }
  52. printf("recv:%s\n",buf);
  53. close(sockfd);
  54. return0;
  55. }

运行:
$ ./bin/server
server is running!
Thread id2505492000accept connect, fd: 4
Thread id1084246368recv:hello world
(注意:线程ID不一样)

$ ./bin/client 10.32.49.10 7092
recv: hello world


信号驱动IO:
使用信号驱动I/O时,当网络套接字可读后,内核通过发送SIGIO信号通知应用进程,于是应用可以开始读取数据。如图:
网络编程--IO模型示例
为了让套接字描述符可以工作于信号驱动I/O模式,应用进程必须完成如下三步设置:
1.注册SIGIO信号处理程序。(安装信号处理器)
2.使用fcntl的F_SETOWN命令,设置套接字所有者。(设置套接字的所有者)
3.使用fcntl的F_SETFL命令,置O_ASYNC标志,允许套接字信号驱动I/O。(允许这个套接字进行信号输入输出)
注意,必须保证在设置套接字所有者之前,向系统注册信号处理程序,否则就有可能在fcntl调用后,信号处理程序注册前内核向应用交付SIGIO信号,导致应用丢失此信号。

在UDP编程中使用信号驱动I/O,此时SIGIO信号产生于下面两种情况:
套接字收到一个数据报。
套接字上发生了异步错误。
因此,当应用因为收到一个UDP数据报而产生的SIGIO时,要么可以调用recvfrom读取该数据报,要么得到一个异步错误。
对于TCP编程,信号驱动I/O就没有太大意义了,因为对于流式套接字而言,有很多情况都可以导致SIGIO产生,而应用又无法区分是什么具体情况导致该信号产生的
信号驱动IO模型在网络编程中极少使用,这里不写例子了,有兴趣的同学可以参考:http://blog.csdn.net/yskcg/article/details/6021275

例子源码打包下载:
http://download.csdn.net/detail/yfkiss/4288465

reference:
UNIX网络编程,第一卷
Linux下 fcntl 函数用法说明
Linux Epoll详解
使用异步 I/O 大大提高应用程序的性能
信号驱动IO

http://blog.csdn.net/byxdaz/article/details/5461142
网络编程--IO模型示例

网络编程--IO模型示例

相关文章: