Linux:多进程版本的服务端分析与实现

服务端开发一般流程

一:函数简介

1.1:fork创建子进程

Linux:虚拟地址空间,程序和进程,创建并回收子进程,孤儿进程和僵尸进程。为什么要回收子进程?_来年秋风起^的博客-CSDN博客

这里详细讲述了进程的创建和资源回收,有兴趣的朋友可以去看看。

1.2:socket创建套接字

1.3:setsockopt设置端口复用

1.4:bind绑定端口和IP

其中IP和port为函数传入参数,端口号必须设定一个确定的端口号。 

   17 int Tcp_socket_bind_listen(const char* IP, unsigned short port)
   18 {
   19   int lfd = socket(AF_INET, SOCK_STREAM, 0);
   20   if(lfd < 0)
   21   {
   22     perror_exit("socket error");
   23   }
   24
   25   int opt = 1;
   26   setsockopt(lfd, SO_REUSEADDR, SOL_SOCKET, &opt, sizeof(opt));
   27
   28   struct sockaddr_in serv;
   29   if(IP){
   30     inet_pton(AF_INET, IP, &serv.sin_addr.s_addr);
   31   }else {
   32     serv.sin_addr.s_addr = htonl(INADDR_ANY);
   33   }
   34   serv.sin_port = htons(port);
   35   int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
   36   if(ret < 0)
   37   {
   38     perror_exit("bind error");
   39   }
   40
   41   listen(lfd, 128); // 设置文件描述符为监听状态
   42
   43   return lfd;
   44 } 

二:设置信号处理函数

2.1:SIGCHLD信号

 SIGCHLD信号,子进程退出时会给父进程发送该信号, 父进程收到该信号后,不管代码执行到那个位置,都会去执行信号处理函数。我们在该信号处理函数中进行对子进程资源的回收。

这里需要注意的是,一定要在创建子进程之前进行信号处理函数的注册。因为在linux操作系统下,进程的执行顺序是随机的,哪个进程抢到cpu的时间片,哪个进程就先执行。这里让父进程在创建子进程前注册信号处理函数,是为了防止在父进程还未执行到注册信号时子进程就已经执行完代码并退出了,这样就会产生僵尸进程。

三:父子进程分工配合实现多进程服务器

父进程负责进行监听,等待客户端链接,拿到与客户端的通信文件描述符,交给子进程进行数据的交换(通信)。

 

这里我只是对客户端发送一个“hello linux”。 

最后附上完整代码:



 12 void perror_exit(const char* str)
 13 {
 14   perror(str);
 15   exit(-1);
 16 }
 17
 18 int Tcp_socket_bind_listen(unsigned short port)
 19 {
 20   // 创建socket套接字 指定网络通信,TCP传输协议
 21   int lfd = socket(AF_INET, SOCK_STREAM, 0);
 22   if(lfd < 0)
 23   {
 24     perror_exit("socket error");
 25   }
 26
 27   // 设置端口复用
 28   int opt = 1;
 29   setsockopt(lfd, SO_REUSEADDR, SOL_SOCKET, &opt, sizeof(opt));
 30
 31   // 绑定lfd与IP和端口
 32   struct sockaddr_in serv;
 33   serv.sin_addr.s_addr = htonl(INADDR_ANY);
 34   serv.sin_port = htons(port);
 35   int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
 36   if(ret < 0)
 37   {
 38     perror_exit("bind error");
 39   }
 40
 41   // 设置文件描述符为监听状态
 42   listen(lfd, 128);
 43
 44   return lfd;
 45 }
 46
 47 int Accept(int fd)
 48 {
 49   int cfd;
 50   do
 51   {
 52     cfd = accept(fd, NULL, NULL);
 53     if(cfd < 0)
 54     {
 55       if(errno == EINTR)
 56       {
 57         continue;
 58       }
 59       return -1;
 60     }
 61
 62   }while(0);
 63   return cfd;
 64 }
 66 void sighandle(int signo)
 67 {
 68   pid_t pid ;
 69   while(1)
 70   {
 71     pid = waitpid(-1, NULL, WNOHANG);
 72     if(pid > 0)
 73     {
 74       printf("child pid ==[%d] signo == [%d]\n", pid, signo);
 75     }
 76     else
 77     {
 78       break;
 79     }
 80   }
 81 }
 82
 83 int main()
 84 {
 85   // 创建监听文件描述符
 86   int lfd = Tcp_socket_bind_listen(9999);
 87
 88   // 注册信号捕主捉函数
 89   struct sigaction act;
 90   act.sa_flags = 0;
 91   sigemptyset(&act.sa_mask);
 92   act.sa_handler = sighandle;
 93   sigaction(SIGCHLD, &act, NULL);
 94
 95   while(1)
 96   {
 97     int cfd = Accept(lfd);
 98     pid_t pid = fork();
 99     if(pid) // 父进程
100     {
101       close(cfd);
102     }
103
104     if(!pid) // 子进程
105     {
106       write(cfd, "hello linux", 11);
107       close(cfd);
108       break;
109     }
110
111   }
112
113   close(lfd);
114
115   return 0;
116 }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值