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

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 客户端和服务器的源代码

    在Linux操作系统中,Socket是一种进程间通信(IPC)机制,广泛用于网络编程,它提供了标准接口,使得应用程序能够发送和接收数据。本篇将详细解析Linux Socket客户端和服务器的源代码,帮助理解其工作原理。 一、...

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

    `select`系统调用会帮助服务器检测哪些Socket准备好了进行读写操作,从而实现多进程间的实时通信。 客户端(Client)需要建立与服务器的连接,然后通过连接发送和接收数据。在这个例子中,假设有两个客户端(Client...

    Linux下Socket 多进程多客户端通信

    在Linux操作系统中,Socket编程...总之,Linux下的Socket多进程多客户端通信涉及到了进程创建、并发处理、同步机制、Socket通信以及进程间通信等多个方面。理解并掌握这些知识点,对于构建高效稳定的网络服务至关重要。

    Linux上实现基于Socket_的多进程实时通信

    通过这种方式,Linux上的Socket多进程实时通信得以实现,确保了进程间的高效、实时的数据交换。这种通信模型适用于需要多个进程协作的系统,如分布式计算、实时数据共享等应用场景。然而,实际应用中还需要考虑错误...

    易语言linux多进程tcp服务器

    《易语言Linux多进程TCP服务器详解》 在IT领域,构建高效的网络服务是至关重要的,尤其是在服务器端。这里我们将深入探讨一个使用易语言在Linux环境下实现的多进程TCP服务器。易语言,作为一款中文编程环境,以其...

    实战Linux socket编程Linux Socket Programming By Example

    这本书通过实例展示了如何在Linux环境下进行网络通信,涵盖了从基础的socket创建、连接到高级的多线程、多进程并发处理等核心知识点。源代码的提供为读者提供了实践和学习的宝贵材料。 首先,我们要理解什么是...

    linux下的socket聊天室程序

    在Linux操作系统中,Socket是一种进程间通信机制,它允许不同进程或者网络间的进程进行通信。本项目"Linux下的socket聊天室程序"就是基于Socket编程实现的一个简单多用户交互平台。这个程序可以支持多个客户端同时...

    LinuxSocket示例代码

    在IT行业中,Linux Socket是进行网络通信的重要工具,尤其对于系统和网络程序员来说,理解和掌握Linux Socket编程至关重要。本示例代码提供了客户端(client)和服务器端(server)的实现,帮助初学者深入理解如何在...

    socket 多进程实例

    标题中的"socket多进程实例"意味着我们将使用Socket接口来创建并管理多个独立的进程,每个进程可以同时处理一个或多个客户端连接。多进程模型允许服务端充分利用多核处理器的计算能力,提高系统并行处理能力,但同时...

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

    在本资源"易语言源码易语言linux多进程tcp服务器源码.rar"中,包含了一个使用易语言编写的适用于Linux系统的多进程TCP服务器的源代码。这个源代码库为学习和理解多进程网络编程提供了很好的实践案例。 首先,我们要...

    linux socket、驱动、进程编程

    在Linux操作系统中,Socket、...无论是网络服务、底层硬件交互还是多任务处理,Linux Socket、驱动和进程编程都是不可或缺的技术栈。在实际开发中,还需要结合具体的场景和需求,灵活运用这些知识,解决复杂的问题。

    linux多进程tcp服务器.rar

    在Linux系统中,多进程TCP服务器是一种常见的网络编程模型,用于构建高性能、高并发的网络服务。本资源“linux多进程tcp服务器.rar”提供了一套用易语言编写的多进程TCP服务器源码,旨在帮助开发者理解和实践这一...

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

    在给定的标题“易语言linux多进程tcp服务器源码”中,我们可以看到这个资源是用易语言在Linux环境下编写的,实现了TCP(Transmission Control Protocol)服务器功能,它支持多进程并发处理客户端连接,这是一种常见...

    实战Linux Socket编程

    在实践中,你还将学习到错误处理、套接字选项、多线程/多进程并发处理连接、异步I/O、套接字复用以及高级特性如TCP的Keepalive、linger选项、套接字缓冲区大小调整等。 通过阅读"实战Linux Socket编程",你将有机会...

    Linux Socket教程.zip

    Linux Socket学习(十六).txt和Linux Socket学习(十七).txt可能涉及到了更高级的主题,如多路复用I/O,如select()、poll()或epoll(),这些工具可以帮助程序同时处理多个Socket连接。 Linux Socket学习(十四)....

    linuxsocket.zip

    10. **多线程或异步处理**:在实际应用中,服务器通常需要同时处理多个客户端连接,可以利用多线程或多进程或者异步I/O模型(如epoll)来提高并发性能。 这个压缩包中的“linuxsocket”代码示例,可以帮助开发者...

    Linux socket双机通信

    综上所述,Linux Socket双机通信涉及到网络协议、Socket编程接口、服务器和客户端的角色分配、操作系统如何处理网络通信等多个方面。理解并掌握这些知识点,对于进行Unix/Linux环境下的网络程序设计至关重要。

    Linux Socket Programming (Linux 套接字编程)

    - **多线程与多进程编程** 5. **Socket编程中的错误处理** - **常见错误及其解决方法** 6. **Socket编程示例** - **简单服务器与客户端实现** - **复杂应用示例** #### 知识点详细解析: **1. Socket编程...

    linux下socket和fork结合使用的例子

    总结来说,`socket`和`fork`在Linux下的结合使用,允许服务器高效地处理多个并发客户端请求。每个客户端请求都会生成一个新的子进程,确保了请求处理的并发性和隔离性。这样的设计模式在多用户交互式应用,如Web...

    linux socket 实战编程pdf及源码

    3. **多线程/多进程模型**:在高并发场景下,如何利用多线程或多进程来处理客户端请求。 4. **信号驱动I/O**:如何利用SIGIO信号处理网络事件。 5. **非阻塞I/O和事件驱动编程**:如使用epoll实现高效的I/O事件监听...

Global site tag (gtag.js) - Google Analytics