如下介绍一个并发回射客户端/服务器的雏形,所谓回射:就是客户端输入一条数据,服务器端读取并显示,然后服务器端再把刚读取的信息发送回客户端进行显示。示意图如下:

Linux 并发服务器雏形总结

 

所谓并发服务器:就是一个服务器可以同时为多个连入的客户端提供服务,示意图如下:

Linux 并发服务器雏形总结

 

如下主要介绍两种实现并发回射服务器的方式,一种是通过子进程方式实现并发,一种是通过I/O多路转接实现并发。

并发服务器(1)[子进程方式]

  1 [root@benxintuzi tcp]# cat echoserv_childprocess.c
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <sys/socket.h>
  5 #include <netinet/in.h>
  6 #include <arpa/inet.h>
  7 #include <stdlib.h>
  8 #include <string.h>
  9 #include <errno.h>
 10 #include <stdio.h>
 11 
 12 #define ERR_EXIT(message)       \
 13         do      \
 14         {       \
 15                 perror(message);        \
 16                 exit(EXIT_FAILURE);     \
 17         } while(0)
 18 
 19 /* 回射服务 */
 20 void echoserv(int conn)
 21 {
 22         char recvbuf[1024];
 23         while (1)
 24         {
 25                 memset(recvbuf, 0, sizeof(recvbuf));
 26                 int ret;
 27                 if ((ret = read(conn, recvbuf, sizeof(recvbuf))) == -1)
 28                         ERR_EXIT("read");
 29                 if (ret == 0)   /* client closed */
 30                 {
 31                         printf("client closed.\n");
 32                         break;
 33                 }
 34                 
 35                 fputs(recvbuf, stdout);
 36                 if (write(conn, recvbuf, ret) != ret)
 37                         ERR_EXIT("write");
 38         }
 39         exit(EXIT_SUCCESS);
 40 }
 41 
 42 
 43 int main(void)
 44 {
 45         /* 创建一个监听套接字 */
 46         int listen_fd;
 47         if ((listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
 48                 ERR_EXIT("socket");
 49 
 50         /* 初始化服务器地址 */
 51         struct sockaddr_in serv_addr;
 52         memset(&serv_addr, 0, sizeof(serv_addr));
 53         serv_addr.sin_family = AF_INET;
 54         serv_addr.sin_port = htons(5188);
 55         serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 56         /**
 57         serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 58         inet_aton("127.0.0.0", &serv_addr.sin_addr); */
 59 
 60         /* 设置地址重复利用,使得服务器不必等待TIME_WAIT状态消失就可以重启 */
 61         int on = 1;
 62         if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
 63                 ERR_EXIT("setsockopt");
 64 
 65         /* 将服务器地址绑定到监听套接字上 */
 66         if (bind(listen_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
 67                 ERR_EXIT("bind");
 68 
 69         /* 监听进入的连接 */
 70         if (listen(listen_fd, SOMAXCONN) == -1)
 71                 ERR_EXIT("listen");
 72 
 73         /* 初始化一个客户端地址用于保存接入的客户端 */
 74         struct sockaddr_in clit_addr;
 75         memset(&clit_addr, 0, sizeof(clit_addr));
 76         socklen_t clit_len = sizeof(clit_addr);
 77     
 78         pid_t pid;
 79         int conn;
 80         while (1)
 81         {
 82                 /* 从已连接队列(保存已完成三次握手的连接)中返回第一个连接 */
 83                 /* 将返回的客户端连接保存在clit_addr中 */
 84                 if ((conn = accept(listen_fd, (struct sockaddr*)&clit_addr, &clit_len)) == -1)
 85                         ERR_EXIT("accept");
 86                         printf("client(ip = %s, port = %d) connected.\n", inet_ntoa(clit_addr.sin_addr), ntohs(clit_addr.sin_port));
 87         
 88                 /* 创建子进程用于回射服务 */
 89                 if (( pid = fork()) == -1)
 90                         ERR_EXIT("fork");
 91                 if (pid == 0)   /* 子进程,每接入一个客户端,就创建一个子进程进行回射服务,这样就可以实现并发处理了 */
 92                 {
 93                         /* 子进程只负责回射服务,不负责连接客户端,因此需要关闭监听套接字 */
 94                         close(listen_fd); 
 95 
 96                         /* 进行回射服务 */
 97                         echoserv(conn);
 98                 }
 99                 else    /* 父进程 */
100                         close(conn);
101         }  
102  
103         return 0;
104 }
View Code

相关文章:

  • 2021-05-23
  • 2021-04-17
  • 2023-04-01
  • 2022-02-04
  • 2021-12-10
  • 2021-05-23
猜你喜欢
  • 2021-07-30
  • 2021-12-23
  • 2022-12-23
  • 2021-12-20
  • 2022-12-23
  • 2021-06-17
  • 2021-11-09
相关资源
相似解决方案