• 10.01


    服务器

    1. #include<myhead.h>
    2. //键盘输入事件
    3. int keybord_events(fd_set readfds)
    4. {
    5. char buf[128] = "";
    6. int sndfd = -1; //从终端获取一个文件描述符,发送数据给该文件描述符对应的客户端
    7. bzero(buf, sizeof(buf));
    8. int res = scanf("%d %s", &sndfd, buf);
    9. while(getchar() != 10);
    10. if(res != 2) //终端输入的数据格式错误
    11. {
    12. printf("输入数据的格式错误,:fd string\n");
    13. return -1;
    14. }
    15. if(sndfd<=2 || FD_ISSET(sndfd, &readfds)==0) //判断文件描述符的合法性
    16. {
    17. printf("非法的文件描述符:sndfd=%d\n", sndfd);
    18. return -1;
    19. }
    20. if(send(sndfd, buf, sizeof(buf), 0) < 0)
    21. {
    22. perror("send");
    23. return -1;
    24. }
    25. printf("send success\n");
    26. return 0;
    27. }
    28. //客户端连接事件
    29. int cliConnect_events(int sfd, struct sockaddr_in saveCin[], fd_set *preadfds, int *pmaxfd)
    30. {
    31. int newfd = -1;
    32. struct sockaddr_in cin; //存储客户端的地址信息
    33. socklen_t addrlen = sizeof(cin); //真实的地址信息结构体的大小
    34. newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
    35. if(newfd < 0)
    36. {
    37. perror("newfd");
    38. return -1;
    39. }
    40. printf("[%s:%d]客户端连接成功 newfd=%d\n", \
    41. inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
    42. saveCin[newfd] = cin; //将cin另存到newfd对应的下标位置去
    43. FD_SET(newfd, preadfds); //将newfd添加到集合中
    44. *pmaxfd = *pmaxfd>newfd ? *pmaxfd:newfd; //更新maxfd
    45. return 0;
    46. }
    47. //客户端交互事件
    48. int cliRcvSnd_events(int fd, struct sockaddr_in* saveCin, fd_set *preadfds, int* pmaxfd)
    49. {
    50. char buf[128] = "";
    51. //清空字符串
    52. bzero(buf, sizeof(buf)); //memset
    53. //接收
    54. ssize_t res = recv(fd, buf, sizeof(buf), 0);
    55. if(res < 0)
    56. {
    57. perror("recv");
    58. return -1;
    59. }
    60. else if(0 == res)
    61. {
    62. printf("[%s:%d]客户端下线 newfd=%d\n", \
    63. inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd);
    64. close(fd); //关闭文件描述符
    65. FD_CLR(fd, preadfds); //将文件描述符从集合中剔除
    66. while(FD_ISSET(*pmaxfd, preadfds)==0 && (*pmaxfd)-->=0);
    67. return 0;
    68. }
    69. printf("[%s:%d] newfd=%d : %s\n", \
    70. inet_ntoa(saveCin[fd].sin_addr), ntohs(saveCin[fd].sin_port), fd, buf);
    71. //发送
    72. strcat(buf, "*_*");
    73. if(send(fd, buf, sizeof(buf), 0) < 0)
    74. {
    75. perror("send");
    76. return -1;
    77. }
    78. printf("send success\n");
    79. return 0;
    80. }
    81. int main(int argc, const char *argv[])
    82. {
    83. int sfd=socket(AF_INET,SOCK_STREAM,0);
    84. if(sfd<0)
    85. {
    86. perror("socket error");
    87. return -1;
    88. }
    89. printf("socket success\n");
    90. //允许端口快速复用
    91. int reuse=1;
    92. if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
    93. {
    94. perror("复用失败 error");
    95. return -1;
    96. }
    97. printf("复用成功\n");
    98. //绑定地址和端口
    99. struct sockaddr_in sin;
    100. sin.sin_family=AF_INET;
    101. sin.sin_port=htons(8888);
    102. sin.sin_addr.s_addr=inet_addr("127.0.0.1");
    103. //绑定服务器
    104. if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
    105. {
    106. perror("bind error");
    107. return -1;
    108. }
    109. //设置监听模式
    110. if(listen(sfd,128)<0)
    111. {
    112. perror("listen error");
    113. return -1;
    114. }
    115. //创建集合
    116. fd_set readfds,tempfds;
    117. //清空
    118. FD_ZERO(&readfds);
    119. //添加集合
    120. FD_SET(0,&readfds);
    121. FD_SET(sfd,&readfds);
    122. int maxfd=sfd;
    123. int s_res=-1;
    124. ssize_t res=-1;
    125. char buf[128]="";
    126. struct sockaddr_in saveCin[1024];
    127. while(1)
    128. {
    129. tempfds =readfds;
    130. s_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
    131. if(s_res<0)
    132. {
    133. perror("select error");
    134. return -1;
    135. }
    136. else if(0==s_res)
    137. {
    138. printf("time out,,\n");
    139. break;
    140. }
    141. for(int i=0; i<=maxfd; i++)
    142. {
    143. if(FD_ISSET(i, &tempfds) == 0)
    144. continue;
    145. //能运行到当前位置,则说明i所代表的文件描述符在集合中
    146. if(0 == i) //0在集合中
    147. {
    148. printf("触发键盘输入事件\n");
    149. keybord_events(readfds);
    150. }
    151. else if(sfd == i) //sfd在集合中
    152. {
    153. printf("触发客户端连接事件\n");
    154. cliConnect_events(sfd, saveCin, &readfds, &maxfd);
    155. }
    156. else
    157. {
    158. printf("触发客户端交互事件\n");
    159. cliRcvSnd_events(i, saveCin, &readfds, &maxfd);
    160. }
    161. }
    162. }
    163. if(close(sfd) < 0)
    164. {
    165. perror("close");
    166. return -1;
    167. }
    168. return 0;
    169. }

    客户端

    1. #include <myhead.h>
    2. #define PORT 8888 //1024~49151
    3. #define IP "127.0.0.1"
    4. int main(int argc, const char *argv[])
    5. {
    6. //创建流失套接字
    7. int cfd=socket(AF_INET,SOCK_STREAM,0);
    8. if(cfd<0)
    9. {
    10. perror("socket");
    11. return -1;
    12. }
    13. //填充服务器的ip地址信息结构体
    14. struct sockaddr_in sin;
    15. sin.sin_family=AF_INET;
    16. sin.sin_port=htons(PORT);
    17. sin.sin_addr.s_addr=inet_addr(IP);
    18. //连接服务器
    19. if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0)
    20. {
    21. perror("connect");
    22. return -1;
    23. }
    24. printf("连接服务器成功\n");
    25. char buf[128];
    26. //与服务器交互
    27. while(1)
    28. {
    29. bzero(buf,sizeof(buf));
    30. fgets(buf,sizeof(buf),stdin);
    31. buf[strlen(buf)-1]='\0';
    32. if(send(cfd,buf,sizeof(buf),0)<0)
    33. {
    34. perror("send");
    35. return -1;
    36. }
    37. if(0==strlen(buf))
    38. {
    39. break;
    40. }
    41. printf("向服务器发送消息成功\n");
    42. bzero(buf,sizeof(buf));
    43. if(recv(cfd,buf,sizeof(buf),0)<0)
    44. {
    45. perror("recv");
    46. return -1;
    47. }
    48. printf("服务器:%s\n",buf);
    49. }
    50. //关闭客户端
    51. close(cfd);
    52. return 0;
    53. }

    结果

  • 相关阅读:
    第十章 设置结构化日志记录(二)
    Dubbo与Zookeeper关系
    centos8升级宝塔导致的openssl系列问题
    面试--并发多线程基础
    嵌入式开发学习之--用蜂鸣器来传递摩斯码
    Serializable自定义序列化测试
    Vue的路由使用,Node.js下载安装及环境配置教程 (超级详细)
    平均年薪20W,自动化测试工程师这么吃香?
    二聚乳酸-羟基乙酸共聚物聚乙二醇 PLGA-PEG-PLGA
    Spring中的批处理:数据处理的瑞士军刀
  • 原文地址:https://blog.csdn.net/m0_70569664/article/details/133467681