• 国庆作业 day 10.1


     使用select完成TCP并发服务器

    1. #include "myhead.h"
    2. #define ERR_MSG(msg) do{\
    3. printf("%d\n",__LINE__);\
    4. perror(msg);\
    5. }while(0)
    6. #define PORT 3696
    7. #define IP "192.1168.10.22"
    8. int main(int argc, const char *argv[])
    9. {
    10. //套接字
    11. int sfd=socket(AF_INET,SOCK_STREAM,0);
    12. if(sfd==-1)
    13. {
    14. ERR_MSG("socket");
    15. return -1;
    16. }
    17. //允许端口复用
    18. int reuse=1;
    19. if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
    20. {
    21. ERR_MSG("setsockopt");
    22. return -1;
    23. }
    24. //绑定服务器
    25. struct sockaddr_in sin;
    26. sin.sin_family=AF_INET;
    27. sin.sin_port=htons(PORT);
    28. sin.sin_addr.s_addr=inet_addr(IP);
    29. if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
    30. {
    31. ERR_MSG("bind");
    32. return -1;
    33. }
    34. //设置监听状态
    35. if(listen(sfd,128)==-1)
    36. {
    37. ERR_MSG("listen");
    38. return -1;
    39. }
    40. fd_set readfds,tempfds;
    41. //清空
    42. FD_ZERO(&readfds);
    43. //文件描述符
    44. FD_SET(0,&readfds);
    45. FD_SET(sfd,&readfds);
    46. struct sockaddr_in cin;
    47. socklen_t addrlen=sizeof(cin);
    48. int newfd=-1;
    49. char buf[32];
    50. ssize_t res=0;
    51. int s_res=-1;
    52. int maxfd=sfd;
    53. int sndfd=-1;
    54. struct sockaddr_in save[1024];
    55. while(1)
    56. {
    57. tempfds =readfds;
    58. maxfd=maxfd>newfd?maxfd:newfd;
    59. s_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
    60. if(s_res == -1){
    61. ERR_MSG("select");
    62. return -1;
    63. }else if(s_res == 0){
    64. printf("time out\n");
    65. break;
    66. }
    67. for(int i = 0;i <= maxfd;i++){
    68. if(FD_ISSET(i,&tempfds) == 0)
    69. continue;
    70. if(0 == i){
    71. printf("触发键盘输入事件\n");
    72. bzero(buf,sizeof(buf));
    73. int ret = scanf("%d %s",&sndfd,buf);
    74. if(ret != 2){
    75. printf("您的输入格式有误:sndfd buf\n");
    76. return -1;
    77. }
    78. if(sndfd <= 2 || FD_ISSET(sndfd,&readfds) == 0){
    79. printf("您输入的文件描述符不合法 snfd = %d\n",sndfd);
    80. return -1;
    81. }
    82. //发送
    83. if(send(sndfd,buf,sizeof(buf),0) == -1){
    84. ERR_MSG("send");
    85. return -1;
    86. }
    87. printf("send success!\n");
    88. }else if(sfd == i){
    89. printf("触发客户端连接事件\n");
    90. //获取一个已经完成的客户端信息,生成一个新的文件描述符 accept
    91. newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
    92. if(newfd == -1){
    93. ERR_MSG("accept");
    94. return -1;
    95. }
    96. printf("[%s:%d]客户端链接成功! newfd = %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
    97. save[newfd] = cin;
    98. FD_SET(newfd,&readfds);
    99. }else{
    100. printf("触发接收客户端数据事件\n");
    101. //接收
    102. bzero(buf,sizeof(buf));
    103. res = recv(i,buf,sizeof(buf),0);
    104. if(res == -1){
    105. ERR_MSG("recv");
    106. return -1;
    107. }else if(res == 0){
    108. printf("[%s:%d]客户端已下线! newfd = %d\n",inet_ntoa(save[i].sin_addr),ntohs(save[i].sin_port),i);
    109. close(i);
    110. FD_CLR(i,&readfds);
    111. while(FD_ISSET(maxfd,&readfds) == 0 && maxfd-->=0);
    112. continue;
    113. }
    114. printf("[%s:%d] newfd = %d buf = %s \n",inet_ntoa(save[i].sin_addr),ntohs(save[i].sin_port),i,buf);
    115. //发送
    116. if(send(i,buf,sizeof(buf),0) == -1){
    117. ERR_MSG("send");
    118. return -1;
    119. }
    120. printf("send success!\n");
    121. }
    122. }
    123. }
    124. //关闭文件描述符
    125. if(close(sfd)<0){
    126. ERR_MSG("close");
    127. return -1;
    128. }
    129. if(close(newfd) < 0){
    130. ERR_MSG("close");
    131. return -1;
    132. }
    133. return 0;
    134. }

  • 相关阅读:
    Flutter快学快用23 架构原理:为什么 Flutter 性能更佳
    leetcode9. 回文数(C++)
    SpringCloud的新闻资讯项目09 --- 用户行为-需求和接口文档
    1017 Queueing at Bank
    DP 优化方法合集
    在不能升级版本的情况下,解决k8s证书到期且续约只有1年的问题
    【1107】
    信息学奥赛一本通:2042:【例5.10】稀疏矩阵
    【C++面向对象】8. 继承
    Linux ubuntu 20.04.5 Server安装远程桌面
  • 原文地址:https://blog.csdn.net/HYL1234511/article/details/133465338