• day38:网编day5, IO多路复用


    一、select的TCP服务器:

    1. #include <myhead.h>
    2. #define ERR_MSG(msg) do{\
    3. fprintf(stderr,"__%d__\n",__LINE__);\
    4. perror(msg);\
    5. }while(0)
    6. #define IP "192.168.114.110"
    7. #define PORT 8888
    8. int main(int argc, const char *argv[])
    9. {
    10. //创建流式套接字socket
    11. int sfd;
    12. if((sfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
    13. {
    14. ERR_MSG("socket");
    15. return -1;
    16. }
    17. printf("socket success sfd = %d\n",sfd);
    18. //允许端口快速被复用
    19. int reuse =1;
    20. if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
    21. {
    22. ERR_MSG("setsockopt");
    23. return -1;
    24. }
    25. printf("允许端口被快速复用成功\n");
    26. //填充地址信息结构体给bind函数使用
    27. struct sockaddr_in sin;
    28. sin.sin_family = AF_INET;
    29. sin.sin_port = htons(PORT); //服务器端口
    30. sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
    31. //绑定服务器的地址信息
    32. if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
    33. {
    34. ERR_MSG("bind");
    35. return -1;
    36. }
    37. printf("[%s:%d]服务器绑定成功\n",IP,PORT);
    38. //将套接字调整为监听模式
    39. if(listen(sfd,128) < 0)
    40. {
    41. ERR_MSG("listen");
    42. return -1;
    43. }
    44. printf("listen success\n");
    45. int judge;
    46. ssize_t len = 0;
    47. int newfd=-1,maxfd=sfd;
    48. char buf[128] = ""; //字符串搬运工
    49. struct sockaddr_in cin;
    50. struct sockaddr_in clidata[1024]; //创建数组来保存newfd的cin,防止多个客户端覆盖地址信息
    51. socklen_t addrlen=sizeof(cin);
    52. fd_set readfds,tmpfds;
    53. FD_ZERO(&readfds);
    54. FD_SET(0,&readfds);
    55. FD_SET(sfd,&readfds);
    56. while(1)
    57. {
    58. tmpfds = readfds;
    59. //如果没有文件描述符准备就绪则阻塞,如果有则数组中只剩下已经准备就绪的文件描述符
    60. judge=select(maxfd+1,&tmpfds,NULL,NULL,NULL);
    61. if(judge < 0)
    62. {
    63. ERR_MSG("select");
    64. return -1;
    65. }
    66. else if(0 == judge)
    67. {
    68. printf("time out\n");
    69. return -1;
    70. }
    71. for(int i=0;i<=maxfd;i++)
    72. {
    73. if(FD_ISSET(i,&tmpfds) == 0)
    74. continue;
    75. if(0 == i )
    76. {
    77. //当文件描述符为0时,表示终端输入有数据
    78. printf("触发终端输入事件\n");
    79. bzero(buf,sizeof(buf));
    80. fgets(buf,sizeof(buf),stdin);
    81. buf[strlen(buf)-1]=0;
    82. printf("buf = %s\n",buf);
    83. /*
    84. if(FD_ISSET(newfd,&readfds))
    85. {
    86. if(send(newfd,buf,sizeof(buf),0)<0)
    87. {
    88. ERR_MSG("send");
    89. return -1;
    90. }
    91. printf("send success\n");
    92. }
    93. */
    94. }else if(sfd == i)
    95. {
    96. //当文件描述符为sfd时,表示有客户端连接
    97. printf("触发客户端连接事件\n");
    98. if((newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen)) < 0)
    99. {
    100. ERR_MSG("accept");
    101. return -1;
    102. }
    103. printf("[%s:%d]客户端连接成功 newfd = %d\n",\
    104. inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
    105. //将对应文件描述符的地址信息保存到数组对应下标中
    106. clidata[newfd] = cin;
    107. //把newfd加入监听队列中
    108. FD_SET(newfd,&readfds);
    109. maxfd = maxfd>newfd?maxfd:newfd;
    110. }else{
    111. bzero(buf,sizeof(buf));
    112. len = recv(i,buf,sizeof(buf),0);
    113. if(len < 0)
    114. {
    115. ERR_MSG("recv");
    116. return -1;
    117. }else if(0 == len)
    118. {
    119. printf("[%s:%d]客户端已下线,newfd = %d\n",\
    120. inet_ntoa(clidata[i].sin_addr),ntohs(clidata[i].sin_port),i);
    121. //关闭文件描述符
    122. close(i);
    123. //将文件描述符从队列中剔除
    124. FD_CLR(i,&readfds);
    125. //更新最大文件描述符
    126. while(FD_ISSET(maxfd,&readfds) == 0 && (maxfd--) >= 0);
    127. continue;
    128. }
    129. printf("[%s:%d]接收成功,newfd = %d:buf = %s\n",\
    130. inet_ntoa(clidata[i].sin_addr),ntohs(clidata[i].sin_port),i,buf);
    131. strcat(buf,">-<");
    132. if(send(i,buf,sizeof(buf),0) < 0)
    133. {
    134. ERR_MSG("send");
    135. return -1;
    136. }
    137. printf("send success\n");
    138. }
    139. }
    140. }
    141. close(sfd);
    142. return 0;
    143. }

    二、select的客户端

    1. #include <myhead.h>
    2. #define ERR_MSG(msg) do{\
    3. fprintf(stderr,"__%d__\n",__LINE__);\
    4. perror(msg);\
    5. }while(0)
    6. #define IP "192.168.114.110" //服务器IP
    7. #define PORT 8888 //服务器端口号
    8. int main(int argc, const char *argv[])
    9. {
    10. //创建流式套接字
    11. int cfd;
    12. if((cfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
    13. {
    14. ERR_MSG("socket");
    15. return -1;
    16. }
    17. printf("socket success cfd = %d",cfd);
    18. //非必须绑定
    19. //填充地址信息结构体给connect使用
    20. struct sockaddr_in sin;
    21. sin.sin_family = AF_INET;
    22. sin.sin_port = htons(PORT); //服务器端口号
    23. sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
    24. if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
    25. {
    26. ERR_MSG("connect");
    27. return -1;
    28. }
    29. printf("[%s:%d]服务器绑定成功\n",IP,PORT);
    30. int judge;
    31. ssize_t len = 0;
    32. char buf[128]="";
    33. fd_set readfds,tmpfds;
    34. FD_ZERO(&readfds);
    35. FD_SET(0,&readfds);
    36. FD_SET(cfd,&readfds);
    37. while(1)
    38. {
    39. tmpfds = readfds;
    40. judge = select(cfd+1,&tmpfds,NULL,NULL,NULL);
    41. if(judge < 0)
    42. {
    43. ERR_MSG("select");
    44. return -1;
    45. }else if(0 == judge)
    46. {
    47. printf("time out\n");
    48. return -1;
    49. }
    50. if(FD_ISSET(0,&readfds)) //写事件触发,终端输入给服务器发送
    51. {
    52. printf("触发写事件\n");
    53. bzero(buf,sizeof(buf));
    54. fgets(buf,sizeof(buf),stdin);
    55. buf[strlen(buf)-1]=0;
    56. if(send(cfd,buf,sizeof(buf),0) < 0)
    57. {
    58. ERR_MSG("send");
    59. return -1;
    60. }
    61. printf("send success buf=%s\n",buf);
    62. }
    63. if(FD_ISSET(cfd,&readfds))
    64. {//读时间触发,从服务器读取数据
    65. printf("触发读事件\n");
    66. bzero(buf,sizeof(buf));
    67. if((len = recv(cfd,buf,sizeof(buf),0)) < 0)
    68. {
    69. ERR_MSG("recv");
    70. return -1;
    71. }
    72. else if(0 == len)
    73. {
    74. printf("[%s:%d]服务器已下线\n",IP,PORT);
    75. break;
    76. }
    77. printf("recv success buf=%s\n",buf);
    78. }
    79. }
    80. close(cfd);
    81. return 0;
    82. }

  • 相关阅读:
    乐观锁和悲观锁各自应用场景
    香港电信级中立机房服务器租赁服务——跨境互联新篇章
    关于spring嵌套事务,我发现网上好多热门文章持续性地以讹传讹
    使用Element UI 的el-pagination组件实现分页效果
    点云从入门到精通技术详解100篇-雨雾环境下多传感器融合SLAM方法
    C++Day5
    【微软漏洞分析】MS10-013 Microsoft DirectShow 中的漏洞可能允许远程执行代码
    【100天精通Python】Day63:Python可视化_Matplotlib绘制子图,子图网格布局属性设置等示例+代码
    深度学习论文: Segment Any Anomaly without Training via Hybrid Prompt Regularization
    PaO2/FiO2在临床中的应用 氧合指数
  • 原文地址:https://blog.csdn.net/wxmchong/article/details/132612397