• 十月一日作业


    1. #include<myhead.h>
    2. #define ERR_MSG(msg) do{\
    3. fprintf(stderr,"__%d__:",__LINE__);\
    4. perror(msg);\
    5. }while(0)
    6. #define PORT 6666 //端口号,范围1024~49151
    7. #define IP "192.168.114.140" //本机IP,ifconfig
    8. int main(int argc, const char *argv[])
    9. {
    10. //创建流式套接字 socket
    11. int sfd=socket(AF_INET,SOCK_STREAM,0);
    12. if(sfd<0)
    13. {
    14. ERR_MSG("socket");
    15. return -1;
    16. }
    17. printf("socket create 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. //真实的地址信息结构体根据地址族指定 AF_INET:man 7 ip
    28. struct sockaddr_in sin;
    29. sin.sin_family=AF_INET; //必须填AF_INET
    30. sin.sin_port=htons(PORT); //端口号的网络字节序
    31. sin.sin_addr.s_addr=inet_addr(IP); //本机IP
    32. //绑定服务器的地址信息————>必须绑定 bind
    33. if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
    34. {
    35. ERR_MSG("bind");
    36. return -1;
    37. }
    38. printf("bind success\n");
    39. //将套接字设置为被动监听状态 listen
    40. if(listen(sfd,128)<0)
    41. {
    42. ERR_MSG("listen");
    43. return -1;
    44. }
    45. printf("listen success\n");
    46. //创建一个读集合
    47. fd_set readfds,tempfds;
    48. //fd_set本质上是一个结构体,结构体中有一个整形数组。
    49. //若不清空,则会存有随机值,可能会随机到有效的,但不需要监测的文件描述符
    50. //清空集合
    51. FD_ZERO(&readfds);
    52. //将需要监测的文件描述符添加到集合中
    53. FD_SET(0,&readfds);
    54. FD_SET(sfd,&readfds);
    55. int maxfd=sfd; //存储最大的文件描述符
    56. int s_res=-1;
    57. ssize_t res=-1;
    58. char buf[128]="";
    59. int newfd=-1;
    60. struct sockaddr_in cin; //存储客户端的地址信息
    61. socklen_t addrlen=sizeof(cin); //真实的地址信息结构体的大小
    62. struct sockaddr_in saveCin[1024]; //备份连接成功的客户端的地址信息,用下标来对应文件描述符
    63. while(1)
    64. {
    65. tempfds=readfds;
    66. //执行IO多路复用函数
    67. s_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
    68. if(s_res<0)
    69. {
    70. ERR_MSG("select");
    71. return -1;
    72. }
    73. else if(0==s_res)
    74. {
    75. printf("time out,,\n");
    76. break;
    77. }
    78. printf("__%d__\n",__LINE__);
    79. //能运行到当前位置,则代表select函数接触阻塞,即代表集合中有文件描述符准备就绪
    80. //此时集合中会只剩下产生事件的文件描述符,例如:
    81. //0号准备就绪,则集合中会只剩下0
    82. //sfd准备就绪,则集合中只会剩下sfd
    83. //0和sfd均准备就绪,则集合中会剩下0和sfd
    84. //只需要判断集合中剩下哪个文件描述符,走对应的处理函数即可;
    85. for(int i=0;i<=maxfd;i++)
    86. {
    87. if(FD_ISSET(i,&tempfds)==0)
    88. {
    89. continue;
    90. }
    91. //能运行到当前位置,则说明i所代表的文件描述符在集合中
    92. if(0==i) //0在集合中
    93. {
    94. printf("触发键盘输入事件\n");
    95. bzero(buf,sizeof(buf));
    96. fgets(buf,sizeof(buf),stdin);
    97. buf[strlen(buf)-1]=0;
    98. printf(":%s\n",buf);
    99. }
    100. else if(sfd==i) //sfd在集合中
    101. {
    102. printf("触发客户端连接事件\n");
    103. newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
    104. if(newfd<0)
    105. {
    106. ERR_MSG("newfd");
    107. return -1;
    108. }
    109. printf("[%s:%d]客户端连接成功 newfd=%d\n",\
    110. inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
    111. saveCin[newfd]=cin; //将cin另存到newfd对应的下标位置去
    112. FD_SET(newfd,&readfds); //将newfd添加到集合中
    113. maxfd=maxfd>newfd ? maxfd:newfd; //更新maxfd
    114. }
    115. else
    116. {
    117. printf("触发客户端交互事件\n");
    118. //清空字符串
    119. bzero(buf,sizeof(buf)); //或memset函数
    120. //接收
    121. res=recv(i,buf,sizeof(buf),0);
    122. if(res<0)
    123. {
    124. ERR_MSG("recv");
    125. return -1;
    126. }
    127. else if(0==res)
    128. {
    129. printf("[%s:%d]客户端下线 newfd=%d\n",\
    130. inet_ntoa(saveCin[i].sin_addr),ntohs(saveCin[i].sin_port),i);
    131. //关闭文件描述符
    132. close(i);
    133. //将文件描述符从集合中剔除
    134. FD_CLR(i,&readfds);
    135. //由于剔除的文件描述符可能是最大文件描述符,所以要更新maxfd
    136. while(FD_ISSET(maxfd,&readfds)==0 && (maxfd--)>=0);
    137. continue;
    138. }
    139. printf("[%s:%d] newfd=%d : %s\n",\
    140. inet_ntoa(saveCin[i].sin_addr),ntohs(saveCin[i].sin_port),i,buf);
    141. //发送
    142. strcat(buf,">_<");
    143. if(send(i,buf,sizeof(buf),0)<0)
    144. {
    145. ERR_MSG("send");
    146. return -1;
    147. }
    148. printf("send success\n");
    149. }
    150. }
    151. }
    152. //关闭文件名描述符
    153. if(close(sfd)<0)
    154. {
    155. ERR_MSG("close");
    156. return -1;
    157. }
    158. return 0;
    159. }

  • 相关阅读:
    [激光原理与应用-19]:《激光原理与技术》-5- 激光器的增益、损耗、自激振荡条件
    【附源码】Python计算机毕业设计师生信息交流指导系统
    Java中JVM的xmx和xms配置成一样的好处
    AUTOSAR中的Crypto Stack(一)--概述
    初识Java 18-2 泛型
    spring创建bean的三种方式
    华北工控EMB3581 瑞芯微Rockchip RK3568,python部署rknn_toolkit_lite2
    [附源码]计算机毕业设计大学生心理健康测评系统
    MySQL修改时区
    Scientific Reports|比较转录组分析揭示了杀菌剂氰烯菌酯对尖孢镰刀菌的抗性调控机制和杀菌活性
  • 原文地址:https://blog.csdn.net/2301_77616453/article/details/133468858