• 十月一日作业


    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. }

  • 相关阅读:
    华为云云耀云服务器L实例评测|基于L实例使用Docker部署MySQL服务并连接MySQL—phpMyAdmin管理工具
    【Python】科研代码学习:九 parser,argparse,HfArgumentParser
    RocketMQ的tag过滤和sql过滤
    【数据库系统概论】作业4 第四章 习题6|7 、第五章 习题6
    【C语言进阶】动态内存管理常见错误
    Web蜜罐
    Android在ActionBar上添加返回以及其它按钮的方法
    12.PGL图学习之项目实践(UniMP算法实现论文节点分类、新冠疫苗项目实战,助力疫情)[系列九]
    前端的小组件
    互联网上有哪些适合上班族的副业?
  • 原文地址:https://blog.csdn.net/2301_77616453/article/details/133468858