本章将带你掌握异步IO事件处理原理。

5-1 通过fork的方式实现高性能网络服务器

图片.png图片.png
图片.png
fork_tcp_server1.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #define PORT 8888
  8. #define MESSAGE_SIZE 1024
  9. int main(){
  10. int ret = -1;
  11. int pid;
  12. int socket_fd = -1;
  13. int curpos = 0;
  14. int backlog = 10;
  15. int flag;
  16. struct sockaddr_in local_addr, remote_addr;
  17. //create a tcp socket
  18. socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  19. if ( socket_fd == -1 ){
  20. perror("create socket error");
  21. exit(1);
  22. }
  23. //set option of socket
  24. ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag));
  25. if ( ret == -1 ){
  26. perror("setsockopt error");
  27. }
  28. //set local address
  29. local_addr.sin_family = AF_INET;
  30. local_addr.sin_port = htons(PORT);
  31. local_addr.sin_addr.s_addr = INADDR_ANY;
  32. bzero(&(local_addr.sin_zero), 8);
  33. //bind socket
  34. ret = bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
  35. if(ret == -1 ) {
  36. perror("bind error");
  37. exit(1);
  38. }
  39. ret = listen(socket_fd, backlog);
  40. if ( ret == -1 ){
  41. perror("listen error");
  42. exit(1);
  43. }
  44. //create a sub process
  45. pid = fork();
  46. for(;;){
  47. //子进程
  48. if( pid==0 ){
  49. int accept_fd = -1;
  50. char in_buf[MESSAGE_SIZE] = {0,};
  51. int addr_len = sizeof( struct sockaddr_in );
  52. //accept an new connection
  53. accept_fd = accept( socket_fd, (struct sockaddr *)&remote_addr, &addr_len );
  54. for(;;){
  55. memset(in_buf, 0, MESSAGE_SIZE);
  56. ret = recv(accept_fd ,&in_buf, MESSAGE_SIZE, 0);
  57. if(ret == 0){
  58. break;
  59. }
  60. printf( "receive message:%s\n", in_buf );
  61. send(accept_fd, (void*)in_buf, MESSAGE_SIZE, 0);
  62. }
  63. printf("close client connection...\n");
  64. close(accept_fd);
  65. }
  66. //parent process
  67. sleep(1000);
  68. }
  69. if(pid != 0 ){
  70. printf("quit server...\n");
  71. close(socket_fd);
  72. }
  73. return 0;
  74. }

fork_tcp_server2.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #define PORT 8111
  8. #define MESSAGE_SIZE 1024
  9. int main(){
  10. int ret = -1;
  11. int pid;
  12. int socket_fd = -1;
  13. int accept_fd = -1;
  14. int curpos = 0;
  15. int backlog = 10;
  16. int flag = 1;
  17. struct sockaddr_in local_addr, remote_addr;
  18. //create a tcp socket
  19. socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  20. if ( socket_fd == -1 ){
  21. perror("create socket error");
  22. exit(1);
  23. }
  24. //set option of socket
  25. ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
  26. if ( ret == -1 ){
  27. perror("setsockopt error");
  28. }
  29. //set local address
  30. local_addr.sin_family = AF_INET;
  31. local_addr.sin_port = htons(PORT);
  32. local_addr.sin_addr.s_addr = INADDR_ANY;
  33. bzero(&(local_addr.sin_zero), 8);
  34. //bind socket
  35. ret = bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
  36. if(ret == -1 ) {
  37. perror("bind error");
  38. exit(1);
  39. }
  40. ret = listen(socket_fd, backlog);
  41. if ( ret == -1 ){
  42. perror("listen error");
  43. exit(1);
  44. }
  45. for(;;){
  46. int addr_len = sizeof( struct sockaddr_in );
  47. //accept an new connection, block......
  48. accept_fd = accept( socket_fd, (struct sockaddr *)&remote_addr, &addr_len );
  49. //create a sub process
  50. pid = fork();
  51. //子进程
  52. if( pid==0 ){
  53. char in_buf[MESSAGE_SIZE] = {0,};
  54. for(;;){
  55. memset(in_buf, 0, MESSAGE_SIZE);
  56. ret = recv(accept_fd ,&in_buf, MESSAGE_SIZE, 0);
  57. if(ret == 0){
  58. break;
  59. }
  60. printf( "receive message:%s\n", in_buf );
  61. send(accept_fd, (void*)in_buf, MESSAGE_SIZE, 0);
  62. }
  63. printf("close client connection...\n");
  64. close(accept_fd);
  65. }
  66. //parent process
  67. }
  68. if(pid != 0 ){
  69. printf("quit server...\n");
  70. close(socket_fd);
  71. }
  72. return 0;
  73. }

5-2 通过select实现高性能服务器

图片.png
图片.png
图片.png

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #define PORT 8888
  9. #define FD_SIZE 1024
  10. #define MESSAGE_SIZE 1024
  11. int main(){
  12. int ret = -1;
  13. int pid;
  14. int accept_fd = -1;
  15. int socket_fd = -1;
  16. int accept_fds[FD_SIZE] = {-1, };
  17. int curpos = -1;
  18. int maxpos = 0;
  19. int backlog = 10;
  20. int flags = 1; //open REUSEADDR option
  21. int max_fd = -1;
  22. fd_set fd_sets;
  23. int events=0;
  24. struct sockaddr_in local_addr, remote_addr;
  25. //create a tcp socket
  26. socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  27. if ( socket_fd == -1 ){
  28. perror("create socket error");
  29. exit(1);
  30. }
  31. //set option of socket
  32. ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
  33. if ( ret == -1 ){
  34. perror("setsockopt error");
  35. }
  36. //NONBLOCK
  37. flags = fcntl(socket_fd, F_GETFL, 0);
  38. fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
  39. //set local address
  40. local_addr.sin_family = AF_INET;
  41. local_addr.sin_port = htons(PORT);
  42. local_addr.sin_addr.s_addr = INADDR_ANY;
  43. bzero(&(local_addr.sin_zero), 8);
  44. //bind socket
  45. ret = bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
  46. if(ret == -1 ) {
  47. perror("bind error");
  48. exit(1);
  49. }
  50. ret = listen(socket_fd, backlog);
  51. if ( ret == -1 ){
  52. perror("listen error");
  53. exit(1);
  54. }
  55. max_fd = socket_fd; //每次都重新设置 max_fd
  56. for(int i=0; i< FD_SIZE; i++){
  57. accept_fds[i] = -1;
  58. }
  59. for(;;) {
  60. FD_ZERO(&fd_sets); //清空sets
  61. FD_SET(socket_fd, &fd_sets); //将socket_fd 添加到sets
  62. for(int k=0; k < maxpos; k++){
  63. if(accept_fds[k] != -1){
  64. if(accept_fds[k] > max_fd){
  65. max_fd = accept_fds[k];
  66. }
  67. printf("fd:%d, k:%d, max_fd:%d\n", accept_fds[k], k, max_fd);
  68. FD_SET(accept_fds[k], &fd_sets); //继续向sets添加fd
  69. }
  70. }
  71. //遍历所有的fd
  72. events = select( max_fd + 1, &fd_sets, NULL, NULL, NULL );
  73. if(events < 0) {
  74. perror("select");
  75. break;
  76. }else if(events == 0){
  77. printf("select time out ......");
  78. continue;
  79. }else if( events ){
  80. printf("events:%d\n", events);
  81. if( FD_ISSET(socket_fd, &fd_sets)){ // 如果来的是新连接
  82. printf("listen event :1\n");
  83. int a = 0;
  84. for( ; a < FD_SIZE; a++){
  85. if(accept_fds[a] == -1){
  86. curpos = a;
  87. break;
  88. }
  89. }
  90. if(a == FD_SIZE){
  91. printf("the connection is full!\n");
  92. continue;
  93. }
  94. int addr_len = sizeof( struct sockaddr_in );
  95. accept_fd = accept(socket_fd, (struct sockaddr *)&remote_addr, &addr_len); //创建一个新连接的fd
  96. int flags = fcntl(accept_fd, F_GETFL, 0); //取出新连接的 fd 的相关选项
  97. fcntl(accept_fd, F_SETFL, flags|O_NONBLOCK); //设置为非阻塞
  98. accept_fds[curpos] = accept_fd;
  99. if(curpos+1 > maxpos){
  100. maxpos = curpos + 1;
  101. }
  102. if(accept_fd > max_fd){
  103. max_fd = accept_fd;
  104. }
  105. printf("new connection fd:%d, curpos = %d \n",accept_fd, curpos);
  106. }
  107. for(int j=0; j < maxpos; j++ ){
  108. if( (accept_fds[j] != -1) && FD_ISSET(accept_fds[j], &fd_sets)){ //有事件时
  109. printf("accept event :%d, accept_fd: %d\n",j, accept_fds[j]);
  110. char in_buf[MESSAGE_SIZE];
  111. memset(in_buf, 0, MESSAGE_SIZE);
  112. int ret = recv(accept_fds[j], &in_buf, MESSAGE_SIZE, 0);
  113. if(ret == 0){
  114. close(accept_fds[j]);
  115. accept_fds[j] = -1;
  116. }
  117. printf( "receive message:%s\n", in_buf );
  118. send(accept_fds[j], (void*)in_buf, MESSAGE_SIZE, 0);
  119. }
  120. }
  121. }
  122. }
  123. printf("quit server...\n");
  124. close(socket_fd);
  125. return 0;
  126. }

5-3 再论select函数

图片.png
图片.png