• 10.1select并发服务器以及客户端


    服务器

    1. #include
    2. //do-while只是为了不让花括号单独存在,并不循环
    3. #define ERR_MSG(msg) do{\
    4. fprintf(stderr,"%d:",__LINE__);\
    5. perror(msg);\
    6. }while(0);
    7. #define PORT 8888//端口号1024-49151
    8. #define IP "192.168.2.54"//本机IP,终端输入ifconfig可得
    9. int main(int argc, const char *argv[])
    10. {
    11. //创建流式套接字 socket
    12. int sfd = socket(AF_INET,SOCK_STREAM,0);
    13. if(sfd<0){
    14. //printf("%d:",__LINE__);
    15. //perror("socket error");
    16. ERR_MSG("socket");
    17. return -1;
    18. }
    19. printf("socket create success sfd=%d\n",sfd);
    20. //允许端口快速的被复用
    21. int reuse = 1;
    22. if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    23. {
    24. ERR_MSG("setsockopt");
    25. return -1;
    26. }
    27. printf("允许端口快速的被复用成功\n");
    28. //填充地址信息结构体给bind函数绑定
    29. //真是的地址信息结构体根据地址族制定 AF_INET:man 7 ip
    30. struct sockaddr_in sin;
    31. sin.sin_family = AF_INET;//必须填AF_INET
    32. sin.sin_port = htons(PORT);//端口号的网络字节序
    33. sin.sin_addr.s_addr = inet_addr(IP);//本机IP
    34. //绑定服务器的地址信息 -->必须绑定 bind
    35. if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){
    36. ERR_MSG("bind");
    37. return -1;
    38. }//指针类型的强转不会有数据丢失
    39. printf("bind success\n");
    40. //将套接字设置为被动监听状态 listen
    41. if(listen(sfd,128)<0){
    42. ERR_MSG("listen");
    43. return -1;
    44. }
    45. printf("listen success\n");
    46. //定义文件描述符集合
    47. fd_set readfds,tmpfds;
    48. //将文件描述符集合清空
    49. FD_ZERO(&readfds);
    50. //将文件描述符放入集合之中
    51. FD_SET(sfd,&readfds);
    52. FD_SET(0, &readfds);
    53. int maxfd = sfd;
    54. int res;
    55. char buf[128] = "";
    56. struct sockaddr_in cin; //存储客户端的地址信息
    57. socklen_t addrlen = sizeof(cin); //真实的地址信息结构体的大小
    58. //获取一个已经完成的客户端信息,生成一个新的文件描述符 accept
    59. int newfd;
    60. struct sockaddr_in saveCin[1024]; //备份连接成功的客户端的地址信息,用下标来对应地址信息
    61. while(1){
    62. tmpfds = readfds;
    63. //调用select函数
    64. res = select(maxfd+1,&tmpfds, NULL, NULL, NULL);
    65. if(res < 0){
    66. ERR_MSG("select error");
    67. break;
    68. }else if(0 == res){
    69. printf("time out\n");
    70. break;
    71. }else{
    72. for(int i=0; i<=maxfd; i++){
    73. if(0==FD_ISSET(i, &tmpfds)){
    74. continue;
    75. }else if(-1==FD_ISSET(i, &tmpfds)){
    76. ERR_MSG("FD_ISSET error");
    77. break;
    78. }
    79. if(0==i){
    80. //终端输入
    81. printf("从终端读取成功::");
    82. fgets(buf,sizeof(buf),stdin);
    83. buf[strlen(buf)-1] = 0;
    84. printf("%s\n",buf);
    85. }
    86. else if(sfd == i){
    87. if((newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen))<0){
    88. ERR_MSG("accept");
    89. return -1;
    90. }
    91. printf("[%s:%d]客户端链接成功 newfd = %d\n",\
    92. inet_ntoa(cin.sin_addr),\
    93. ntohs(cin.sin_port),newfd);
    94. saveCin[newfd] = cin; //将cin另存到下标为文件描述符的位置
    95. //将newfd添加到集合中
    96. FD_SET(newfd, &readfds);
    97. //更新maxfd
    98. maxfd = maxfd>newfd?maxfd:newfd;
    99. }else{
    100. if(FD_ISSET(i, &readfds)){
    101. //清空字符串
    102. bzero(buf,sizeof(buf)); //memset
    103. //接收
    104. res = recv(i, buf, sizeof(buf) ,0);
    105. if(res<0){
    106. ERR_MSG("recv");
    107. return -1;
    108. }else if(0==res){
    109. printf("[%s:%d]客户端下线 newfd=%d\n",\
    110. inet_ntoa(saveCin[i].sin_addr),\
    111. ntohs(saveCin[i].sin_port),i);
    112. //将文件描述符从集合中踢出
    113. FD_CLR(i, &readfds);
    114. //由于踢出的文件描述符可能是最大文件描述符,更新maxfd
    115. /* for(; maxfd>=0; maxfd--){
    116. if(FD_ISSET(maxfd, &readfds)){
    117. break;
    118. }
    119. } */
    120. while(FD_ISSET(maxfd, &readfds)==0 && maxfd-->=0);
    121. //关闭文件描述符
    122. close(i);
    123. continue;
    124. }
    125. printf("[%s:%d]客户端消息 newfd=%d:%s\n",\
    126. inet_ntoa(saveCin[i].sin_addr),\
    127. ntohs(saveCin[i].sin_port),i,buf);
    128. //发送
    129. strcat(buf,">_<");
    130. if(send(i,buf,strlen(buf),0)<0){
    131. ERR_MSG("send");
    132. return -1;
    133. }
    134. printf("send success\n");
    135. }
    136. }
    137. }
    138. /*
    139. //如果是终端输入就绪
    140. if(FD_ISSET(0,&tmpfds)){
    141. printf("从终端读取成功::");
    142. fgets(buf,sizeof(buf),stdin);
    143. buf[strlen(buf)-1] = 0;
    144. printf("%s\n",buf);
    145. }
    146. //如果是客户端连接就绪
    147. if(FD_ISSET(sfd,&tmpfds)){
    148. if((newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen))<0){
    149. ERR_MSG("accept");
    150. return -1;
    151. }
    152. printf("[%s:%d]客户端链接成功 newfd = %d\n",\
    153. inet_ntoa(cin.sin_addr),\
    154. ntohs(cin.sin_port),newfd);
    155. saveCin[newfd] = cin; //将cin另存到下标为文件描述符的位置
    156. //将newfd添加到集合中
    157. FD_SET(newfd, &readfds);
    158. //更新maxfd
    159. maxfd = maxfd>newfd?maxfd:newfd;
    160. }
    161. for(int i=4; i<=maxfd; i++){
    162. if(FD_ISSET(i, &readfds)){
    163. //清空字符串
    164. bzero(buf,sizeof(buf)); //memset
    165. //接收
    166. res = recv(i, buf, sizeof(buf) ,0);
    167. if(res<0){
    168. ERR_MSG("recv");
    169. return -1;
    170. }else if(0==res){
    171. printf("[%s:%d]客户端下线 newfd=%d\n",\
    172. inet_ntoa(saveCin[i].sin_addr),\
    173. ntohs(saveCin[i].sin_port),i);
    174. //将文件描述符从集合中踢出
    175. FD_CLR(i, &readfds);
    176. //由于踢出的文件描述符可能是最大文件描述符,更新maxfd
    177. for(; maxfd>=0; maxfd--){
    178. if(FD_ISSET(maxfd, &readfds)){
    179. break;
    180. }
    181. }
    182. while(FD_ISSET(maxfd, &readfds)==0 && maxfd-->=0);
    183. //关闭文件描述符
    184. close(i);
    185. continue;
    186. }
    187. printf("[%s:%d]客户端消息 newfd=%d:%s\n",\
    188. inet_ntoa(saveCin[i].sin_addr),\
    189. ntohs(saveCin[i].sin_port),i,buf);
    190. //发送
    191. strcat(buf,">_<");
    192. if(send(i,buf,strlen(buf),0)<0){
    193. ERR_MSG("send");
    194. return -1;
    195. }
    196. printf("send success\n");
    197. }
    198. }*/
    199. }
    200. }
    201. //关闭文件描述符
    202. close(newfd);
    203. if(close(sfd)<0){
    204. ERR_MSG("close");
    205. return -1;
    206. }
    207. return 0;
    208. }

    服务器:

    1. #include
    2. //do-while只是为了不让花括号单独存在,并不循环
    3. #define ERR_MSG(msg) do{\
    4. fprintf(stderr,"%d:",__LINE__);\
    5. perror(msg);\
    6. }while(0);
    7. #define PORT 8888//端口号1024-49151
    8. #define IP "192.168.2.54"//本机IP,终端输入ifconfig可得
    9. int main(int argc, const char *argv[])
    10. {
    11. //创建流式套接字 socket
    12. int cfd = socket(AF_INET,SOCK_STREAM,0);
    13. if(cfd<0){
    14. //printf("%d:",__LINE__);
    15. //perror("socket error");
    16. ERR_MSG("socket");
    17. return -1;
    18. }
    19. printf("socket create success sfd=%d\n",cfd);
    20. //填充服务器的地址信息结构体给connect函数连接
    21. //相连接哪个服务器就输入哪个服务器的地址信息
    22. //真是的地址信息结构体根据地址族制定 AF_INET:man 7 ip
    23. struct sockaddr_in sin;
    24. sin.sin_family = AF_INET;//必须填AF_INET
    25. sin.sin_port = htons(PORT);//服务器绑定的端口号的网络字节序
    26. sin.sin_addr.s_addr = inet_addr(IP);//服务器绑定的IP
    27. socklen_t addrlen = sizeof(sin);
    28. //连接指定服务器 connect
    29. if(connect(cfd,(struct sockaddr*)&sin,addrlen)<0){
    30. ERR_MSG("connect");
    31. return -1;
    32. }
    33. char buf[128] = "";
    34. ssize_t res = 0;
    35. //定义文件描述符集合
    36. fd_set readfds,tmpfds;
    37. //初始化集合
    38. FD_ZERO(&readfds);
    39. //把cfd加入集合
    40. FD_SET(cfd, &readfds);
    41. //把标准输入加入集合
    42. FD_SET(0, &readfds);
    43. int ret = -1;
    44. while(1){
    45. tmpfds = readfds;
    46. ret = select(cfd+1, &tmpfds, NULL, NULL, NULL);
    47. if(ret<0){
    48. ERR_MSG("select error");
    49. break;
    50. }else if(0 == ret){
    51. printf("time out\n");
    52. break;
    53. }else{
    54. if(FD_ISSET(0, &tmpfds)){
    55. //说明有来自终端的输入,需要发送
    56. //清空字符串
    57. bzero(buf,sizeof(buf)); //memset
    58. printf("请输入>> ");
    59. fgets(buf,sizeof(buf),stdin);
    60. buf[strlen(buf)-1] = 0;
    61. //发送
    62. strcat(buf,">_<");
    63. if(send(cfd,buf,strlen(buf),0)<0){
    64. ERR_MSG("send");
    65. return -1;
    66. }
    67. printf("send success\n");
    68. }
    69. if(FD_ISSET(cfd, &tmpfds)){
    70. //套接字文件的接收缓冲区有数据,需要接收
    71. //说明有来自终端的输入,需要发送
    72. //清空字符串
    73. bzero(buf,sizeof(buf)); //memset
    74. //接收
    75. res = recv(cfd, buf, sizeof(buf) ,0);
    76. if(res<0){
    77. ERR_MSG("recv");
    78. return -1;
    79. }else if(0==res){
    80. printf("[%s:%d]服务器下线 cfd=%d\n",\
    81. inet_ntoa(sin.sin_addr),\
    82. ntohs(sin.sin_port),cfd);
    83. break;
    84. }
    85. printf("[%s:%d]服务器消息 cfd=%d:%s\n",\
    86. inet_ntoa(sin.sin_addr),\
    87. ntohs(sin.sin_port),cfd,buf);
    88. }
    89. }
    90. }
    91. /*
    92. while(1){
    93. //清空字符串
    94. bzero(buf,sizeof(buf)); //memset
    95. printf("请输入>> ");
    96. fgets(buf,sizeof(buf),stdin);
    97. buf[strlen(buf)-1] = 0;
    98. //发送
    99. strcat(buf,">_<");
    100. if(send(cfd,buf,strlen(buf),0)<0){
    101. ERR_MSG("send");
    102. return -1;
    103. }
    104. printf("send success\n");
    105. //接收
    106. res = recv(cfd, buf, sizeof(buf) ,0);
    107. if(res<0){
    108. ERR_MSG("recv");
    109. return -1;
    110. }else if(0==res){
    111. printf("[%s:%d]服务器下线 cfd=%d\n",\
    112. inet_ntoa(sin.sin_addr),\
    113. ntohs(sin.sin_port),cfd);
    114. break;
    115. }
    116. printf("[%s:%d]服务器消息 cfd=%d:%s\n",\
    117. inet_ntoa(sin.sin_addr),\
    118. ntohs(sin.sin_port),cfd,buf);
    119. }
    120. */
    121. //关闭文件描述符
    122. //close(newfd);
    123. if(close(cfd)<0){
    124. ERR_MSG("close");
    125. return -1;
    126. }
    127. return 0;
    128. }

    效果:

  • 相关阅读:
    ssm手机销售网站
    Spring-boot-starter-actuator的可视化spring-boot-admin
    Java成王之路】EE初阶第二十一篇: 前端三剑客 JavaScript(WebAPI)
    es从线上库导出数据并导入开发环境
    git clone private repo remote: Repository not found. | git新电脑上clone私有库
    【论文笔记】policy-space response oracles (PSRO)
    Python 获取两个数组中各个坐标点对之间最短的欧氏距离
    初刷leetcode题目(3)——数据结构与算法
    计算机服务器中了勒索病毒怎么解决,勒索病毒解密步骤数据恢复
    公司内部传文件怎么安全——「用绿盾透明加密软件」
  • 原文地址:https://blog.csdn.net/sy311SB/article/details/133468988