• TCP通信并发


    要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。
     
    思路:
      1. 一个父进程,多个子进程
      2.父进程负责等待并接受客户端的连接
      3.子进程:完成通信,接受一个客户端连接,就创建一个子进程用于通信。

    客户端

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main() {
    9. //创建套接字
    10. int fd = socket(AF_INET, SOCK_STREAM, 0);
    11. if(fd == -1) {
    12. perror("socket");
    13. exit(-1);
    14. }
    15. //连接服务器
    16. struct sockaddr_in serverAddr;
    17. inet_pton(AF_INET, "192.168.79.130", &serverAddr.sin_addr.s_addr);
    18. serverAddr.sin_family = AF_INET;
    19. serverAddr.sin_port = htons(9999);
    20. int ret = connect(fd,(struct sockaddr*) &serverAddr, sizeof(serverAddr));
    21. if(ret == -1) {
    22. perror("connect");
    23. exit(-1);
    24. }
    25. //通信
    26. char recvBuf[1024];
    27. int i = 0;
    28. while(1) {
    29. sprintf(recvBuf, "%d\n", i++);
    30. //给服务端发送数据
    31. write(fd, recvBuf, strlen(recvBuf) + 1);
    32. sleep(1);
    33. //接收数据
    34. int len = read(fd, recvBuf, sizeof(recvBuf) + 1);
    35. if(len == -1) {
    36. perror("read");
    37. exit(-1);
    38. } else if(len > 0) {
    39. printf("recv server data : %s\n", recvBuf);
    40. } else if(len == 0) {
    41. //表示服务端断开连接
    42. printf("server closed...\n");
    43. break;
    44. }
    45. }
    46. close(fd);
    47. return 0;
    48. }

    服务端

    1.创建子进程 

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void recycleChild(int arg) {
    10. while(1) {
    11. int ret = waitpid(-1, NULL, WNOHANG);
    12. if(ret == -1) {
    13. // 所有的子进程都回收了
    14. break;
    15. }else if(ret == 0) {
    16. // 还有子进程活着
    17. break;
    18. } else if(ret > 0){
    19. // 被回收了
    20. printf("子进程 %d 被回收了\n", ret);
    21. }
    22. }
    23. }
    24. int main() {
    25. //注册信号捕捉
    26. struct sigaction act;
    27. act.sa_flags = 0;
    28. sigemptyset(&act.sa_mask);
    29. act.sa_handler = recycleChild;
    30. sigaction(SIGCHLD, &act, NULL);
    31. //创建套接字
    32. int lfd = socket(PF_INET, SOCK_STREAM, 0);
    33. if(lfd == -1) {
    34. perror("socket");
    35. exit(-1);
    36. }
    37. struct sockaddr_in saddr;
    38. saddr.sin_addr.s_addr = INADDR_ANY;
    39. saddr.sin_family = AF_INET;
    40. saddr.sin_port = htons(9999);
    41. //绑定
    42. int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
    43. if(ret == -1) {
    44. perror("bind");
    45. exit(-1);
    46. }
    47. //监听
    48. ret = listen(lfd, 8);
    49. if(ret == -1) {
    50. perror("listen");
    51. exit(-1);
    52. }
    53. //不断循环等待客户连接
    54. while(1) {
    55. struct sockaddr_in cliaddr;
    56. int len = sizeof(cliaddr);
    57. int cfd = accept(lfd, (struct sockaddr*) &cliaddr, &len);
    58. if(cfd == -1) {
    59. if(errno == EINTR) {
    60. continue;
    61. }
    62. perror("accept");
    63. exit(-1);
    64. }
    65. //每一个连接进来,创建一个子进程跟客户端通信
    66. pid_t pid = fork();
    67. if(pid == 0) {
    68. //子进程
    69. //获取客户端的信息
    70. char clientIP[16];
    71. inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));
    72. unsigned short cliPort = ntohs(cliaddr.sin_port);
    73. printf("client ip is : %s, port is %d\n", clientIP, cliPort);
    74. //接收客户端发来的信息
    75. char recvBuf[1024] = {0};
    76. while(1) {
    77. int len = read(cfd, &recvBuf, sizeof(recvBuf) + 1);
    78. if(len == -1) {
    79. perror("read");
    80. exit(-1);
    81. } else if(len > 0) {
    82. printf("recv client data is : %s\n", recvBuf);
    83. } else {
    84. printf("client closed...\n");
    85. break;
    86. }
    87. write(cfd, recvBuf, sizeof(recvBuf) + 1);
    88. }
    89. close(cfd);
    90. exit(0);
    91. }
    92. }
    93. close(lfd);
    94. return 0;
    95. }

    2.创建子线程

     

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. struct sockInfo{
    9. int fd;
    10. pthread_t tid;
    11. struct sockaddr_in addr;
    12. };
    13. struct sockInfo sockInfos[128];
    14. void * working(void * arg) {
    15. //子线程和客户端通信 cfd 客户端信息 线程号(封装成一个结构体传入)
    16. //获取客户端信息
    17. struct sockInfo * pinfo = (struct sockInfo *) arg;
    18. char clientIP[16];
    19. inet_ntop(AF_INET, &pinfo->addr.sin_addr.s_addr, clientIP, sizeof(clientIP));
    20. unsigned short cliPort = ntohs(pinfo->addr.sin_port);
    21. printf("client ip is : %s, port is %d\n", clientIP, cliPort);
    22. //接收客户端发来的信息
    23. char recvBuf[1024] = {0};
    24. while(1) {
    25. int len = read(pinfo->fd, &recvBuf, sizeof(recvBuf) + 1);
    26. if(len == -1) {
    27. perror("read");
    28. exit(-1);
    29. } else if(len > 0) {
    30. printf("recv client data is : %s\n", recvBuf);
    31. } else {
    32. printf("client closed...\n");
    33. break;
    34. }
    35. write(pinfo->fd, recvBuf, sizeof(recvBuf) + 1);
    36. }
    37. close(pinfo->fd);
    38. exit(0);
    39. }
    40. int main() {
    41. //创建套接字
    42. int lfd = socket(PF_INET, SOCK_STREAM, 0);
    43. if(lfd == -1) {
    44. perror("socket");
    45. exit(-1);
    46. }
    47. struct sockaddr_in saddr;
    48. saddr.sin_addr.s_addr = INADDR_ANY;
    49. saddr.sin_family = AF_INET;
    50. saddr.sin_port = htons(9999);
    51. //绑定
    52. int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
    53. if(ret == -1) {
    54. perror("bind");
    55. exit(-1);
    56. }
    57. //监听
    58. ret = listen(lfd, 8);
    59. if(ret == -1) {
    60. perror("listen");
    61. exit(-1);
    62. }
    63. //初始化数据
    64. int max = sizeof(sockInfos) / sizeof(sockInfos[0]);
    65. for(int i = 0; i < max; i++) {
    66. bzero(&sockInfos[i], sizeof(sockInfos[i]));
    67. sockInfos[i].fd = -1;
    68. sockInfos[i].tid = -1;
    69. }
    70. //循环等待客户端连接,一旦一个客户端连接进来,就创建一个子线程
    71. while(1) {
    72. struct sockaddr_in cliaddr;
    73. int len = sizeof(cliaddr);
    74. //接收连接
    75. int cfd = accept(lfd, (struct sockaddr*) &cliaddr, &len);
    76. struct sockInfo *pinfo;
    77. for(int i = 0; i < max; i++) {
    78. //从这个数组中找到一个可以用的sockInfo元素
    79. if(sockInfos[i].fd == -1) {
    80. pinfo = &sockInfos[i];
    81. break;
    82. }
    83. if(i == max - 1) {
    84. sleep(1);
    85. i--;
    86. }
    87. }
    88. pinfo->fd = cfd;
    89. memcpy(&pinfo->addr, &cliaddr, len);
    90. //创建子线程
    91. pthread_t tid;
    92. pthread_create(&pinfo->tid, NULL, working, pinfo);
    93. //回收子线程
    94. pthread_detach(pinfo->tid);
    95. }
    96. close(lfd);
    97. return 0;
    98. }

  • 相关阅读:
    rk平台android12系统设置里面互联网选项中的以太网选项点击不了问题
    云原生Kubernetes:K8S安全机制
    libusb开源库使用说明
    22、7大参数自定义线程池(核心线程数,最大核心线程数。。。拒绝策略(4种))
    基于elelemt-ui封装一个表单
    hdfs常用命令行
    Flink DataStream 侧输出流 Side Output
    Java面试八股文宝典:初识数据结构-数组
    How to get ‘kernel config‘ when CONFIG_IKCONFIG is not set ? (Method)
    华为摄像头通过stm32叠加字符串
  • 原文地址:https://blog.csdn.net/ME_Liao_2022/article/details/133657677