select模型用来轮询处理多个连接的读写

    • 给文件描述符设置读写集合
    • 读完之后将对应描述符放入写集合内,下一次循环到来时处理被放入写集合内所有描述符

    问题:

    • 下面server代码在gdb打断的情况下,无法成功进入FD_SET(fds[i], &reads)条件判断
    • 如果直接运行server,再用client连接的话会进入阻塞状态,这里怀疑是某个系统调用阻塞住了进程
      • 因为accept之后,server没有做read调用,client在write之后阻塞在read
    • select是否为阻塞调用取决于timeout [ref]
    • client一旦进程退出主动断开连接,server就会卡死,server.c这里没有做这块逻辑处理

    client.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <sys/types.h>
    5. #include <sys/socket.h>
    6. #include <netinet/in.h>
    7. #include <arpa/inet.h>
    8. #include <sys/time.h>
    9. #include <unistd.h>
    10. #define LEN 1024
    11. const int PORT = 8080;
    12. const char *IP = "127.0.0.1";
    13. struct sockaddr_in server;
    14. int clientSock;
    15. char buf[LEN];
    16. int main() {
    17. clientSock = socket(AF_INET, SOCK_STREAM, 0);
    18. if (clientSock < 0) {
    19. perror("socket");
    20. exit(0);
    21. }
    22. server.sin_family = AF_INET;
    23. server.sin_addr.s_addr = inet_addr(IP);
    24. server.sin_port = htons(PORT);
    25. if (0 > connect(clientSock, (struct sockaddr *)&server, sizeof(server)))
    26. {
    27. perror("connect");
    28. exit(0);
    29. }
    30. while (1) {
    31. memset(buf, 0, LEN);
    32. printf("please input: ");
    33. gets(buf);
    34. write(clientSock, buf, strlen(buf));
    35. memset(buf, 0, LEN);
    36. int ret = read(clientSock, buf, LEN);
    37. buf[ret] = 0;
    38. printf("[+]: %s\n", buf);
    39. }
    40. return 0;
    41. }

    server.c

    1. #include <sys/time.h>
    2. #include <stdio.h>
    3. #include <string.h>
    4. #include <stdlib.h>
    5. #include <sys/socket.h>
    6. #include <netinet/in.h>
    7. #include <arpa/inet.h>
    8. #include <sys/types.h>
    9. #include <unistd.h>
    10. #include <signal.h>
    11. #define LEN 1024
    12. const int PORT = 8080;
    13. struct sockaddr_in client;
    14. struct sockaddr_in local;
    15. int listenSock;
    16. int linkSock = -1;
    17. int fds[64];
    18. int size_client = sizeof(client);
    19. int ListenSock() {
    20. listenSock = socket(AF_INET, SOCK_STREAM, 0);
    21. if (listenSock < 0) {
    22. perror("socket");
    23. exit(1);
    24. }
    25. local.sin_family = AF_INET;
    26. local.sin_port = htons(PORT);
    27. local.sin_addr.s_addr = htonl(INADDR_ANY);
    28. if (0 > bind(listenSock, (struct sockaddr *)&local, sizeof(local))) {
    29. perror("bind");
    30. exit(2);
    31. }
    32. if (0 > listen(listenSock, 5)) {
    33. perror("listen");
    34. exit(3);
    35. }
    36. return listenSock;
    37. }
    38. void Shutdown(int arg) {
    39. int i;
    40. for (i = 0; i < 64; i++) {
    41. close(fds[i]);
    42. }
    43. printf("[-] shutdown !\n");
    44. }
    45. int main() {
    46. listenSock = ListenSock();
    47. signal(SIGTERM, Shutdown);
    48. char buf[LEN];
    49. memset(buf, 0, LEN);
    50. while (1) {
    51. fd_set reads, writes;
    52. int fds_max;
    53. int i = 0;
    54. int fds_num = sizeof(fds) / sizeof(fds[0]);
    55. for (; i < fds_num; i++) {
    56. fds[i] = -1;
    57. }
    58. fds[0] = listenSock;
    59. fds_max = fds[0];
    60. struct timeval times;
    61. while (1) {
    62. FD_ZERO(&reads);
    63. FD_ZERO(&writes);
    64. FD_SET(listenSock, &reads);
    65. times.tv_sec = 1;
    66. times.tv_usec = 0;
    67. for (i = 1; i < fds_num; i++) {
    68. if (fds[i] > 0) {
    69. FD_SET(fds[i], &reads);
    70. if (fds[i] > fds_max) {
    71. fds_max = fds[i];
    72. }
    73. }
    74. }
    75. switch (select(fds_max + 1, &reads, &writes, NULL, &times)) {
    76. case 0:
    77. printf("[-] timeout\n");
    78. break;
    79. case -1:
    80. perror("select");
    81. break;
    82. default:
    83. for (i = 0; i < fds_num; i++) {
    84. if (fds[i] == listenSock && FD_ISSET(fds[i], &reads)) {
    85. linkSock = accept(listenSock, (struct sockaddr *)&client, &size_client);
    86. if (0 > linkSock) {
    87. perror("accept");
    88. continue;
    89. }
    90. for (i = 0; i < fds_max; i++) {
    91. if (0 > fds[i]) {
    92. fds[i] = linkSock;
    93. FD_SET(linkSock, &writes);
    94. break;
    95. }
    96. }
    97. if (i == fds_max - 1) {
    98. printf("[!] fds is full. Please close some links to keep program running successfully.\n");
    99. }
    100. }
    101. else if (fds[i] > 0 && FD_ISSET(fds[i], &writes)) {
    102. memset(buf, 0, LEN);
    103. int ret = read(fds[i], buf, LEN);
    104. if (0 > ret) {
    105. perror("read");
    106. continue;
    107. }
    108. else if (0 == ret) {
    109. printf("[-] client is closed\n");
    110. continue;
    111. }
    112. else {
    113. printf("[+] %s\n", buf);
    114. }
    115. if (0 > write(fds[i], buf, strlen(buf))) {
    116. perror("write");
    117. continue;
    118. }
    119. }
    120. }
    121. break;
    122. }
    123. }
    124. }
    125. return 0;
    126. }