码迷,mamicode.com
首页 > 其他好文 > 详细

TCP服务器程序优化

时间:2021-01-27 13:41:49      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:orm   执行   需要   src   类型   时间   lan   ubunt   点击   

1. 测试

  在我https://www.cnblogs.com/Suzkfly/p/14049687.html这篇博客中提到,按照文种的范例程序测试,在Ubuntu中运行a.out,在windows下用网络调试助手不断的断开重连,在Ubuntu下另开一个终端,运行执行ps -au命令,可以看到每断开重连一次,系统中就会遗留一个进程,如下图:

 技术图片

 2. 修改代码

  在调用recv函数时返回0,因此知道客户端断开连接了,此时需要进行的操作是让子进程退出,父进程重新开始连接,而由于父进程被scanf阻塞了,它不能及时调用到waitpid函数而得知子进程退出了,因此需要将标准输入设置为非阻塞,具体的设置方法参见:https://www.cnblogs.com/Suzkfly/p/14331287.html

  修改后的代码如下:

  1  /**
  2   * filename: tcp_server.c
  3   * author: Suzkfly
  4   * date: 2021-01-25
  5   * platform: Ubuntu
  6   * 配合windows的网络调试工具使用:
  7   *     1、先保证windows与Ubuntu在同一网段且互相能ping通;
  8   *     2、在windows下打开网络调试助手,选择协议类型为TCP Client,远程主机地址为
  9   *        Ubuntu的IP地址,远程主机端口为Ubuntu例程中写的端口,接收设置和发送设
 10   *        置都选择ASCLL。
 11   *     3、运行Ubuntu下的TCP服务器程序;
 12   *     4、网络调试助手上点击“连接”。
 13   *     5、连接成功后在网络调试助手上发送数据,在Ubuntu下的终端上能看到,
 14   *        在Ubuntu下的终端上输入字符串按回车发送,在windows上的网络调试助手上也
 15   *        能看到。
 16   */
 17 #include <stdio.h>
 18 #include <sys/types.h>
 19 #include <sys/socket.h>
 20 #include <string.h>
 21 #include <netinet/in.h>
 22 #include <arpa/inet.h>
 23 #include <sys/wait.h>
 24 #include <unistd.h>
 25 #include <fcntl.h>
 26 
 27 //#define IP_ADDR "127.0.0.1" /* IP地址 */
 28 #define PORT    10000       /* 端口号 */
 29 
 30 int main(int argc, const char *argv[])
 31 {
 32     int sock_fd = 0, confd = 0;
 33     struct sockaddr_in serv_addr;       /* 服务器IP(本机IP) */
 34     struct sockaddr_in client_addr;     /* 客户端IP(连接者IP) */
 35     socklen_t addr_len = sizeof(struct sockaddr_in);
 36     int ret = 0;                        /* 用于接收函数返回值 */
 37     int pid = 0;
 38     char buf[128] = { 0 };              /* 用于存放数据的缓冲区 */
 39     int len = 0;                        /* 发送和接收数据的长度 */
 40     int ret_pid = 0;
 41     int attr = 0;                       /* 文件描述符属性 */
 42     
 43     /* 创建TCP套接字 */
 44     sock_fd = socket(AF_INET, SOCK_STREAM, 0);
 45  
 46     /* 将套接字与IP和端口绑定 */
 47     memset(&serv_addr, 0, sizeof(struct sockaddr_in));
 48     serv_addr.sin_family = AF_INET;
 49     //serv_addr.sin_addr.s_addr = inet_addr(IP_ADDR); /* 绑定IP */
 50     serv_addr.sin_addr.s_addr = 0;                  /* 绑定0就是绑定自己 */
 51     serv_addr.sin_port = htons(PORT);               /* 端口号 */
 52     ret = bind(sock_fd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr_in));
 53     if (ret == 0) {
 54         printf("bind ok\n");
 55     } else {
 56         printf("bind failed\n");
 57         close(sock_fd);
 58         return 0;
 59     }
 60     
 61     /* 让套接字进入被动监听状态 */
 62     ret = listen(sock_fd, 10);
 63     if (ret == 0) {
 64         printf("listen ok\n");
 65     } else {
 66         printf("listen failed\n");
 67         close(sock_fd);
 68         return 0;
 69     }
 70 
 71 re_connect:
 72 
 73     /* 接收客户端请求(阻塞) */
 74     memset(&client_addr, 0, sizeof(client_addr));
 75     printf("accept...\n");
 76     confd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);
 77     printf("confd = %d\n", confd);
 78     if (confd > 0) {
 79         printf("accept ok\n");
 80     } else {
 81         printf("accept failed\n");
 82         close(sock_fd);
 83         return 0;
 84     }
 85     
 86     /* 打印客户端信息 */
 87     printf("addr_len = %d\n", addr_len);
 88     printf("Client IP: %s\n", inet_ntoa(client_addr.sin_addr)); /* IP地址 */
 89     printf("Client Port:%d\n", ntohs(client_addr.sin_port));      /* 端口号 */
 90     
 91     memset(buf, 0, sizeof(buf));
 92     
 93     pid = fork();
 94     
 95     if (pid > 0) {          /* 父进程,发送数据 */
 96         attr = fcntl(STDIN_FILENO, F_GETFL);
 97         attr |= O_NONBLOCK;
 98         fcntl(STDIN_FILENO, F_SETFL, attr);
 99         while (1) {
100             ret_pid = waitpid(-1, NULL, WNOHANG);  /* 用非阻塞的方式等待子进程退出 */
101             if (ret_pid == pid) {
102                 goto re_connect;    /* 重新连接 */
103             }
104             
105             len = read(STDIN_FILENO, buf, sizeof(buf));
106             if (len > 0) {
107                 send(confd, buf, strlen(buf), 0);
108                 memset(buf, 0, sizeof(buf));
109             }
110         }
111     } else if (pid == 0) {  /* 子进程,接收数据 */
112         while (1) {
113             memset(buf, 0, sizeof(buf));
114             len = recv(confd, buf, sizeof(buf), 0);
115             if (len == 0) {     /* 如果recv返回0,则表示远端断开连接 */
116                 break;
117             }
118             printf("len = %d\n", len);
119             printf("data: %s\n", buf);
120         }
121     }
122 }

  通过ps -au命令查看,当客户端连接时存在两个进程,当客户端断开连接时,存在1个进程,不会再出现每次断开重连都会多一个进程的现象。而且断开重连短时间内无法发送数据的问题也顺带解决了。

 

TCP服务器程序优化

标签:orm   执行   需要   src   类型   时间   lan   ubunt   点击   

原文地址:https://www.cnblogs.com/Suzkfly/p/14326811.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!