`
linguanghuan
  • 浏览: 3559 次
社区版块
存档分类
最新评论

Linux Socket 多进程服务器

阅读更多

server.c

#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <signal.h>

#define MAXLINE 1024

// 1:
static void sig_child(int signo)
{
        pid_t pid;
        int status;
        while( (pid=waitpid(-1, &status,WNOHANG)) > 0)   //2: W NO HANG   
        {
                printf("child terminated,pid:%d\n", pid);
                if (WIFEXITED(status))   // W IF EXIT ED // 3:
                {
                        printf("exit code:%d\n",WEXITSTATUS(status));  //4: W EXIT STATUS
                }
        }
}

int main()
{
        int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (listen_fd == -1)
        {
                printf("socket error[%d]:%s\n", errno, strerror(errno));
                exit(errno);
        }

        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(55555);
        if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
        {
                printf("bind error[%d]:%s\n", errno, strerror(errno));
                exit(errno);
        }

        if (listen(listen_fd, 3) == -1)
        {
                printf("listen error[%d]:%s\n", errno, strerror(errno));
                exit(errno);
        }

        //5: catch child terminate signal
        signal(SIGCHLD,sig_child);

        while (1)
        {
                struct sockaddr_in client_addr;
                memset(&client_addr, 0, sizeof(client_addr));
                int len = sizeof(client_addr);
                int client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len);
                if (client_fd == -1)
                {
                        printf("accept error[%d]:%s\n", errno, strerror(errno));
                        sleep(1);
                        continue;
                }

                pid_t pid = fork();
                if (pid < 0)
                {
                        printf("fork error[%d]:%s\n", errno, strerror(errno));
                        continue;
                }else if (pid == 0)    // child process
                {
                        close(listen_fd);   //6:  close no use parent fd in child
                        printf("child process[%d],ppid:%d\n", getpid(), getppid());
                        char rb[100] = {0};
                        int recv_len = recv(client_fd, rb, MAXLINE, 0);
                        if (recv_len == -1)
                        {
                                printf("recv error[%d]:%s\n", errno, strerror(errno));
                                exit(errno);
                        }
                        printf("recv[%d]:%s\n", recv_len, rb);
                        strcat(rb, ", has been received by server, the msg from server");
                        if (send(client_fd, rb, strlen(rb), 0) == -1)
                        {
                                printf("send error[%d]:%s\n", errno, strerror(errno));
                                exit(errno);
                        }
                        printf("send success\n");
                        close(client_fd);
                        exit(0);     // 8
                }
                close(client_fd);   //7: close no use child fd in parent
        }
        close(listen_fd);
}

 

 

1. 为注册信号SIGCHLD 提供的的处理函数

SIGCHLD:子进程结束时, 父进程会收到这个信号。如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情 况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程 来接管)。

 

2. 3  4

函数原型: pid_t waitpid(pid_t pid,int * status,int options);

函数说明:

如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回。

子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数 status 可以设成 NULL。

 

参数 pid:

为欲等待的子进程识别码,其数值意义如下:

pid<-1 等待进程组识别码为 pid 绝对值的任何子进程

pid=-1 等待任何子进程,相当于 wait()

pid=0 等待进程组识别码与目前进程相同的任何子进程

pid>0 等待任何子进程识别码为 pid 的子进程

 

参数status:

为返回的状态

WIFEXITED(status)如果若为正常结束子进程返回的状态,则为真;对于这种情况可执行WEXITSTATUS(status),取子进程传给exit或_eixt的低8位。

WEXITSTATUS(status)取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。

 

参数options:

提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用,比如:

WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID

 

5  signal(SIGCHLD,sig_child); 注册子进程退出信号的处理函数

 如果父进程为注册处理这个信号, 则子进程执行exit后产生僵尸进程,如下

zxnms 18717 16191 0 15:53 pts/0 00:00:00 ./server
zxnms 18719 18717 0 15:53 pts/0 00:00:00 [server] <defunct>
zxnms 18721 18717 0 15:53 pts/0 00:00:00 [server] <defunct>
zxnms 18723 18717 0 15:53 pts/0 00:00:00 [server] <defunct>

 父进程执行wait或waitpid处理僵尸进程。

 或者只有父进程结束,子进程的僵尸进程变成孤儿进程,这些僵尸进程才会被init回收。

在信号处理函数时处理,可以不阻塞父进程的当前任务,只有子进程发出信号时才去处理。

 

6  子进程中关闭没用的父进程的监听socket fd

 

7  父进程中没用到子进程的socket fd,关闭,因为在多进程环境中,这里的close只是将引用计数减1,直到所有进程都close, 引用计数变为0时,内核才发送FIN

 

8 这里要直接退出了,否则子进程后面的语句也是while循环,也会执行到fork,那就不止两层了,会不停嵌套下去,变成子进程的子进程的子进程的子进程......

分享到:
评论

相关推荐

    Linux上实现Socket的多进程实时通信

    但是由于Socket本身不支持同时等待和超时处理,所以它不能直接用来多进程之间的相互实时通信。本文提出一个基于Socket的多进程之间通信的实现方法。原理是建立一个进程专 门用来做为通信服务器(server)来中转各个...

    linux基于多进程的socket通信

    #include &lt;sys/socket.h&gt; #include #include #include #include #include #include #include "../comm/my_recv.h" // 自定义的头文件 #include "../comm/my_recv.c" #define SERVER_IP "127.0.0.1" #define...

    多进程并发服务器实现

    Linux环境下应用进程和Socket套接字设计并发服务器,完成多用户聊天应用程序,这里给出了在Linux环境下的C语言实现完整代码。

    使用多进程的并发服务器

    用多进程实现的并发服务器,c语言,socket,在linux下实现

    (牛客网C++课程)Linux 高并发Web服务器项目实战(带定时检测代码)

    (牛客网C++课程)Linux 高并发Web服务器项目实战(带定时检测代码) 技术框架: 1. 线程池 + 非阻塞 socket + epoll + 事件处理的并发模型 2. 状态机解析HTTP请求 3. 心跳机制 4. 简易日志系统 主要内容: 1. ...

    基于LinuxC和socket的多进程qq聊天程序(支持文件传输)

    本程序实现了以server为主的并发服务器,可以同时和多个客户端聊天,并且支持文件传输的功能

    Fork_Socket:Linux多进程服务器和客户端

    前叉插座Linux多进程服务器和客户端如果您下载此文件你应该修改一些东西包括: C / server.c:20和21行// inet_pton(AF_INET,IP,(struct sockaddr *)&server_addr.sin_addr); //如果选择此选项,则应修改C / ...

    易语言linux多进程tcp服务器源码-易语言

    易语言linux多进程tcp服务器源码

    论文研究-Linux下基于TCP的预先派生子进程服务器的Socket编程 .pdf

    Linux下基于TCP的预先派生子进程服务器的Socket编程,和家强,刘彦隆,描述了客户/服务器模型以及常见的服务器类型--基于TCP的并发服务器。在一个基于TCP回射服务器程序的基础上,结合实际Web应用中的多进

    Linux高性能服务器编程.pdf

    第二部分对高性能服务器编程的核心要素进行了全面深入的剖析,包含Linux网络编程API、高级I/O函数、Linux服务器程序规范、高性能服务器程序框架、I/O复用、信号、定时器、高性能I/O框架库Libevent、多进程编程、多...

    linux服务器客户端1对1聊天

    socket建立套接字,服务器与客户端一对一简单聊天程序

    多进程并发服务器设计

    Linux环境下应用进程和Socket套接字设计并发服务器,完成多用户聊天应用程序,本文档给出了系统设计模型、进程通信接口。

    linux httpserver并发服务器案例,,可参考

    html服务器,使用了socket,多线程实现,,加入了守护进程,-b可进入.. 学习中使用的案例,可能还存在多种bug,仅供参考....代码头有本人联系方式

    linux网络编程

    网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-...

    Linux高性能服务器编程

    第二部分对高性能服务器编程的核心要素进行了全面深入的剖析,包含Linux网络编程API、高级I/O函数、Linux服务器程序规范、高性能服务器程序框架、I/O复用、信号、定时器、高性能I/O框架库Libevent、多进程编程、多...

    Linux高性能服务器编程清晰PDF+源码.7z

    第二部分对高性能服务器编程的核心要素进行了全面深入的剖析,包含Linux网络编程API、高级I/O函数、Linux服务器程序规范、高性能服务器程序框架、 I/O复用、信号、定时器、高性能I/O框架库Libevent、多进程编程、多...

    Linux下基于TCP的预先派生子进程服务器的Socket编程

    在一个基于TCP回射服务器程序的基础上,结合实际Web应用中的多进程服务器模型,考虑到原有的客户/服务器交互存在的问题,改进了客户程序,设计了实现并发功能的客户程序、并发服务器以及预先派生子进程服务器。...

    基于多线程的Linux聊天室系统

    用C语言编程实现linux简单的聊天室功能。  用户程序命名为client.c;服务器程序命名为server.c  绑定端口等信息见实验方法内容;  要求client可以通过socket连接server  在client,提示输入服务器ip  若连接...

    Linux高级程序设计PPT

    10第10章 Linux多线程编程.ppt 11第11章 线程间同步机制.ppt 12第12章 Linux socket网络编程基础 .ppt 13第13章 网络编程工具介绍.ppt 14第14章 网络编程高级应用.ppt 15第15章 构建网络服务器.ppt

    如何编写Linux下的客户机/服务器软件

    Linux多播IP是一种同时向价格进程高效的发送信息的介绍。多播传输中,数据被发送到接收者的多播地址,而不是每个接收者的单播地址,发送者只发送一个...本文将论述如何在 Linux环境下利用Socket实现客户机/服务器通信。

Global site tag (gtag.js) - Google Analytics