精华内容
下载资源
问答
  • 1.TCP循环服务器 ①TCP循环服务器一次只能处理一个客户端的请求。 ②只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求。 ③这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了.因此,TCP...

    1.TCP循环服务器

    ①TCP循环服务器一次只能处理一个客户端的请求。
    ②只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求。
    ③这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了.因此,TCP服务器一般很少用循环服务器模型。
    循环服务器模型:

    socket();
    bind();
    listen();
    while(1){
          accept();
          process();
          close();    
    }
    

    之前我们已经写了一个简单的循环服务器程序,但是如果我们想让多个客户端同时和我们的服务器通信,显然循环服务器是办不到的。为什么办不到呢,因为我们的进程当中有很多阻塞模式的函数比如

    accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen);
    

    如果没有客户端连接我们的服务器我们的程序就会卡在这个函数等待来自客户端的连接不继续执行下面的程序。如果有客户端连接了服务器,代码就继续执行,但是又阻塞在了下面这行代码

    read(connfd, buff, 1024)

    如果没有收到客户端的数据我们就只能一直在这死等,其他啥也干不了。
    如果我们想让一个 TCP 服务器程序同时处理正在侦听网络连接的套接字和已经连接好的套接字,循环服务器更是办不到。那么怎么办呢?这就有了我们的并发服务器。

    2.多进程并发服务器

    并发服务器的实现方法有很多种,我们先用其中的一种方法——多进程,来实现。多进程并发服务器需要我们了解Linux多进程的知识,可以参考这篇文章Linux进程控制

    多进程并发服务器模型:

    socket();
    bind();
    listen();
    while(1){
           accept();
           if(fork() == 0)
           {
                    process();
                    close();
                    exit();
            } 
            close();
    }
    

    学习了Linux进程控制之后我们便有了初步的想法怎么实现并发服务器了,我们可以让父进程一直监听有没有客户端的连接,如果有客户端连接了,就fork()出一个子进程去处理这个连接,而父进程一直监听,一旦有一个新客户端的连接便fork()一个新进程。当客户端断开连接的话我们便通过exit()函数终止处理该客户端的子进程。
    具体代码实现如下:

    #include <sys/shm.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <error.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    
    #define PORT 8080
    
    int n;//存储接收数据的长度 
    struct sockaddr_in cliaddr;//存储客户端的信息
    socklen_t  cliaddrlen = sizeof(cliaddr);
    char buff[1024];
    
    void childProcess(int connfd);
    
    int main()
    {
        int listenfd, connfd;
        struct sockaddr_in servaddr;
    
        pid_t childPid;
    
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(listenfd == -1)
        {
            perror("socket error:");
            exit(1);
        }
        memset(&servaddr, 0, sizeof(servaddr));//使用 sockaddr_in 的时候要把 sin_zero 全部设成零值(使用 bzero()或 memset()函数)。
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(PORT);//将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian) 
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//将主机的无符号长整形数转换成网络字节顺序。
        if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1)
        {
            perror("bind error:");
            exit(1);
        }
        if(listen(listenfd, 10) == -1)
        {
            perror("listen error:");
            exit(1);
        }
        while(1)
        {
            printf("main process start accept!\n");
            connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen);
            if((childPid = fork()) < 0)
            {
                perror(("fork failed"));
                exit(1);
            }
    
            if(!childPid)
            {
    
                close(listenfd);
                childProcess(connfd);
            }
            if(childPid)
            {
                printf("new PID %d process start!\n",childPid);
                close(connfd);
            }
        }
        return 0;
    }
    
    void childProcess(int connfd)
    {
        if(connfd == -1)
        {
            perror("accpet error:");
            exit(1);
        }else
        {
            printf("accept a new client: %s:%d,fd=%d\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port,connfd);
        }
        while(1)
        {
            n = read(connfd, buff, 1024);
            if (n == -1)
            {
                perror("read error:");
                close(connfd);
                exit(1);
            }
            else if (n == 0)
            {
                fprintf(stderr,"client close,fd=%d\n",connfd);
                close(connfd);
                exit(0);
            }
            else
            {
                printf("read message is: %s,fd=%d\n",buff,connfd);
                write(connfd, buff, n);
            }
        }
    
    }
    
    

    3.多进程并发服务器测试

    我们先启动我们的服务器程序
    在这里插入图片描述
    然后我们打开两个网络调试助手代表两个客户端去连接服务器
    先连接第一个
    在这里插入图片描述
    再连接第二个
    在这里插入图片描述
    我们把新创建进程的PID打印了出来,可以用Linux的ps -aux命令确认一下
    在这里插入图片描述
    28597为我们的父进程,28598和28961为我们的子子进程
    在这里插入图片描述
    我们的消息也可以正常的接收只不过是区分不出来来自哪个客户端。
    当我们关闭两个客户端
    在这里插入图片描述
    然后再用ps查看一下我们的这两个进程有没有终止
    在这里插入图片描述
    可以看到我们的两个客户端子进程变为了defunct进程(僵尸进程)。

    在 Linux 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。当用ps命令观察进程的执行状态时,看到这些进程的状态栏为defunct。僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。

    但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。

    展开全文
  • 在Linux中通过流式套接字编程(TCP),实现一个并发服务器的访问回显,适合刚学完Linux套接字编程的朋友进行巩固训练 具体功能: 服务器能够同时连接、处理个客户端的信息 客户端向服务器发送数据之后,服务器...

    说明

    在Linux中通过流式套接字编程(TCP),实现一个并发服务器的访问回显,适合刚学完Linux套接字编程的朋友进行巩固训练
    具体功能:

    • 服务器能够同时连接、处理多个客户端的信息
    • 客户端向服务器发送数据之后,服务器收到数据,然后反手发送给客户端
    • 服务器能够对客户端的退出做出反应,并在客户端退出连接的时候给出提示
    • 服务器能够识别每个客户端发送的信息,在显示的时候加上客户端的IP地址
    • 服务器中能够对已经退出的服务进程作回收处理
    • 客户端能够对服务器的退出作出反应,检测到服务器退出后客户端也退出

    注意事项

    • 多进程并发服务器编程中,每次建立一个套接字连接,都会fork一个进程来处理
    • accept是自带阻塞的,所以fork返回父进程之后,父进程就会阻塞等待下一个已连接套接字
    • 客户端的关闭通过ctrl-c发出的信号(SIGINT)来终止客户端
    • 当客户端终止之后,服务器上对应的服务进程通过exit结束,此时由于服务器的主进程还阻塞在accept中,所以无法及时回收子服务进程,所以通过注册一个信号SIGCHLD处理函数,在信号处理的时候回收僵尸子进程。SIGCHLD是子进程结束的时候发送给父进程的信号,默认忽略。
    • 服务器进程如何检测客户端退出呢?通过recv()函数,当返回值为0的时候,表示客户端已经关闭套接字,即客户端退出。
    • 当服务线程主动关闭的时候,客户端也会通过recv()收到服务器关闭的信息,然后客户端主动退出
    • 关于套接字描述符,因为描述符也算是进程的资源,当套接字描述符的引用值为0的时候,才会关闭套接字,或者是进程退出的时候释放套接字描述符资源
    • 每次fork的时候,都会产生一个对于已经打开的套接字描述符的引用,所以要在进入子服务进程后关闭监听套接字描述符、在主服务进程中关闭已连接套接字描述符、在子服务进程退出的时候关闭已连接套接字描述符、在退出主服务器进程的时候关闭监听套接字描述符,这样才做到了有始有终(fork之后已连接套接字描述符的引用就有两份)在这里插入图片描述

    server.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <errno.h>
    
    #define SERVER_ADDR "172.17.44.154"
    #define BUFSIZE 100
    
    void sigchld_handler(int arg);
    
    int main(int argc, const char *argv[])
    {
        int socket_fd, new_fd;
        struct sockaddr_in server_addr, cli_addr;
        char buf[BUFSIZE];
        int pid;
        struct sigaction sig;
    
        /* 注册中断信号处理函数 */
        sig.sa_handler = sigchld_handler;
        sigaction(SIGCHLD, &sig, NULL);
    
    
        /* 创建套接字,并获取套接字描述符 */
        socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (-1 == socket_fd) {
            perror("socket");
            exit(-1);
        }
    
        /* 绑定地址 */
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(5001);
        inet_pton(AF_INET, SERVER_ADDR, (void*)&server_addr.sin_addr.s_addr);   //地址转换
        if (-1 == bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))) {
            perror("bind");
            exit(-1);
        }
    
        /* 转换为被动连接套接字 */
        if (-1 == listen(socket_fd, 5)) {
            perror("listen");
            exit(-1);
        }
    
    #if 0  //单进程服务器
        /* 获取已连接套接字 */
        socklen_t len = 0;
        new_fd = accept(socket_fd, (struct sockaddr*)&cli_addr, (socklen_t *)&len);
        if (-1 == new_fd) {
            perror("accept");
            exit(-1);
        }
        printf("accept socket!\nclient ip :%s  port:%d\n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port);
    
        while (1) {
            memset(buf, 0, BUFSIZE);
            if (0 == recv(new_fd, buf, BUFSIZE, 0)) {  //接受数据
                printf("the client is closed\n");
                break;
            }
            printf("read:%s\n", buf);
            send(new_fd, buf, BUFSIZE, 0);           //回应客户端
        }
        close(new_fd);
    
    #else   //多进程并发服务器
        while (1) {
    
            socklen_t len = 0;
            new_fd = accept(socket_fd, (struct sockaddr*)&cli_addr, (socklen_t *)&len);   
            if (-1 == new_fd) {
                if (errno == EINTR) continue;   //accept可能会被信号中断
                perror("accept");
                exit(-1);
            }
    
            /* 并发服务器:子进程中进行TCP通信 */
            pid = fork();
            if (pid == -1) {
                perror("fork");
                exit(0);
            } else if (pid == 0) {
                close(socket_fd);         //关闭监听套接字
    
                while (1) {
                    memset(buf, 0, BUFSIZE);
                    if (0 == recv(new_fd, buf, BUFSIZE, 0)) {  //接受数据,只有当客户端主动关闭的时候,才退出线程,还要对关闭之后的子进程
                        printf("the client socket %s is closed\n", inet_ntoa((struct in_addr)cli_addr.sin_addr));
                        close(new_fd);                         //退出之前记得关闭 已连接套接字
                        exit(0);    //通过信号处理函数进行回收                             
                        
                    }
                    getsockname(new_fd, (struct sockaddr*)&cli_addr, (socklen_t *)&len);  //获取连接套接字信息
                    printf("recv client IP:%s data:%s\n", inet_ntoa((struct in_addr)cli_addr.sin_addr), buf);
                    send(new_fd, buf, BUFSIZE, 0);           //回应客户端
                }
    
            } else {
                close(new_fd);   //父进程关闭 已连接套接字
            }
    
        }
        
    #endif
    
        close(socket_fd);
        return 0;
    }
    
    void sigchld_handler(int arg)
    {
        int child_pid;
        if (SIGCHLD == arg) {
            if ((child_pid = waitpid(-1, NULL,  WNOHANG)) == -1) {
                perror("sigchld");
            }
            printf("a client %d is end\n", child_pid);
        }
    
    }
    
    

    client.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #define SERVER_ADDR "172.17.44.154"
    #define BUFSIZE 100
    
    
    
    int main(int argc, const char *argv[])
    {
        int new_fd;
        struct sockaddr_in server_addr;
        char buf[BUFSIZE];
    
        /* 创建套接字,并获取套接字描述符 */
        new_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (-1 == new_fd) {
            perror("socket");
            exit(-1);
        }
    
    
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(5001);
        inet_pton(AF_INET, SERVER_ADDR, (void*)&server_addr.sin_addr.s_addr);
        if (-1 == connect(new_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))) {
            perror("connect");
            exit(-1);
        }
    
        while (1) {
            printf("input:");
            fgets(buf, BUFSIZE, stdin);                 //获取数据
    
            if (-1 == send(new_fd, buf, BUFSIZE, 0)) {  //发送数据
                perror("send");
                close(new_fd);
                exit(-1);
            }
            if (0 == recv(new_fd, buf, BUFSIZE, 0)) {   //收到数据
                printf("server closed\n");
                break;
            }
            printf("recv:%s\n", buf);
        }
        close(new_fd);
    
        return 0;
    }
    
    

    运行截图

    PS:这里是在同一主机下做实验的,所以各个客户端的IP地址都是一样的
    正常运行的状态如下:
    在这里插入图片描述

    当有一个客户端退出时,服务器会显示信息,但是对其他客户端的服务正常进行:
    在这里插入图片描述
    当服务器主动关闭之后,所有客户端都会收到服务器关闭的信息,并且主动退出:
    在这里插入图片描述

    展开全文
  • 进程结束后发送SIGCHLD信号,通过信号捕捉函数捕捉信号终止的信息,在回调函数中完成子进程的回收,避免产生僵尸进程。 2 服务端程序 #include <iostream> #include <arpa/inet.h> #include <sys/...

    1 实现思路

    1. 在父进程中循环accept阻塞等待客户端连接,每接收一个连接请求就创建一个子进程;
    2. 在子进程中实现客户端与服务端的通信;
    3. 子进程结束后发送SIGCHLD信号,通过信号捕捉函数捕捉信号终止的信息,在回调函数中完成子进程的回收,避免产生僵尸进程。

    2 服务端程序

    #include <iostream>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <string.h>
    #include <errno.h>
    
    #define SERV_PORT 9998
    
    using namespace std;
    
    void recycleChild(int sig) { //回调函数,当子进程退出时执行,用来回收子进程,防止僵尸进程
        while(waitpid(-1, NULL, WNOHANG) > 0); //父进程非阻塞式等待所有子进程结束
    }
    
    int main() {
        int lfd, cfd;
        struct sockaddr_in sarrd, caddr; //创建地址结构体,分别用来存放服务端地址信息和客户端地址信息
        pid_t pid;         //创建子进程
    
        //创建临时阻塞信号集
        struct sigaction act; 
        act.sa_flags =0;
        act.sa_handler = recycleChild;
        sigemptyset(&act.sa_mask); //清空临时阻塞信号集
    
        //注册信号
        sigaction(SIGCHLD, &act, NULL);
    
        //创建服务端套接字
        if((lfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(-1);
        }
    
        //为服务端地址结构赋值
        sarrd.sin_family = AF_INET;
        sarrd.sin_port = htons(SERV_PORT);
        sarrd.sin_addr.s_addr = htonl(INADDR_ANY);
    
        //设置端口复用
        socklen_t optval = 1;
        setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
    
        //绑定服务端地址信息
        if(bind(lfd, (struct sockaddr *)&sarrd, sizeof(sarrd)) == -1) {
            perror("bind");
            exit(-1);
        }
    
        //监听socket上的连接
        if(listen(lfd, 8) == -1) {
            perror("listen");
            exit(-1);
        }
    
        char ServerIP[16];
        inet_ntop(AF_INET, &sarrd.sin_addr.s_addr, ServerIP, 16);
        cout << "init success" << endl;
        cout << "host ip: " << ServerIP << ", port: " << ntohs(sarrd.sin_port) << endl;
    
        //不断循环等待客户端连接
        while(1) {
            socklen_t len = sizeof(caddr);
            if((cfd = accept(lfd, (struct sockaddr*)&caddr, &len)) == -1) {
                if(errno == EINTR) continue;
                /*
                进程在一个慢系统调用(slow system call)中阻塞时,当捕获到某个信号且相应信号处理函数
                返回时,这个系统调用被中断,调用返回错误,设置errno为EINTR
                参考:https://blog.csdn.net/benkaoya/article/details/17262053
                */
                perror("accept");
                exit(-1);
            }
            //输出连接客户端信息
            char ClientIP[16];
            inet_ntop(AF_INET, &caddr.sin_addr.s_addr, ClientIP, 16); 
            cout << "client ip: " << ClientIP << ", port: " << ntohs(caddr.sin_port) << endl;
    
            if((pid = fork()) == 0) {
                while(1) {
                    char recvBuf[1024];
                    int len = 0;
                    if((len = read(cfd, recvBuf, sizeof(recvBuf))) > 0) {
                        cout << "(SERVER) recv data: " << recvBuf << "   (from port: " << ntohs(caddr.sin_port)  << ")"<< endl;
                        int i = 0;
                        for(i = 0; i < len; i++) {
                            recvBuf[i] = toupper(recvBuf[i]);
                        }
                        recvBuf[i] = '\0';
                        write(cfd, recvBuf, strlen(recvBuf)); //转为大写后发回
                    }
                    else if(len == 0) {
                        cout << "(SERVER) client, from port: " << ntohs(caddr.sin_port) << " closed..." << endl;
                        break;
                    }
                    else if(len == -1) {
                        perror("read");
                        exit(-1);
                    }
                }            
                close(cfd);
                exit(0);  //退出子进程
            }
            else if(pid > 0) {
                close(cfd);
            }
            else {
                perror("fork");
                exit(-1);
            }
        }
        close(lfd);
        return 0;
    }
    

    3 运行结果

    客户端程序不变,先启动服务端,然后运行两个客户端进行测试:
    客户端连接:
    在这里插入图片描述
    客户端断开:
    在这里插入图片描述

    展开全文
  • 摘要:随着物联网、智能电网、智能移动设备的发展,我们将能在任何时候任何地方获取我们所需的信息,本文设计一款基于ARM-Linux嵌入式系统的多进程并发服务器。它拥有传统服务器的功能,可远程访问和操作,同时又...

    摘要:随着物联网、智能电网、智能移动设备的发展,我们将能在任何时候任何地方获取我们所需的信息,本文设计一款基于ARM-Linux嵌入式系统的多进程并发服务器。它拥有传统服务器的功能,可远程访问和操作,同时又具有体积小、噪声低、低功耗、低成本的优势,非常适合用于智能楼宇的家用服务器。本文引用地址:http://www.eepw.com.cn/article/201609/304671.htm

    目前大家所用的大多是X86服务器,其功能完善、运行速度快、软件支持性好等优点,已被人们普遍认同。但其由于价格昂贵、功耗高、噪声大等原因,一般只应用于工厂、企事业单位,但随着互连网的发展,我们需要更多的小型服务器终端,因此,低成本、低功耗的嵌入式服务器将有极大的应用空间。

    面向连接的并发服务器是目前Linux网络服务器的主流形式。它采用主、从服务器的工作方式,能较好地解决了网络中客户进程的并发请求问题。目前在嵌入式领域,基于ARM技术的微处理器应用约占据了32位RISC微处理器80%以上的市场份额,同时,ARM处理器和嵌入式Linux的结合也正变得越来越紧密,在工业控制、消费类电子产品、通信系统、无线系统等各类产品市场都可以看到ARM与Linux相结合的身影。因此,本文介绍了一种基于ARM-Linux嵌入式系统的多进程并发服务器设计。

    1 并发服务器原理及框架

    1. 1 基本的C/S服务模型

    相互通信的网络程序通常可以分为客户端和服务器端两部分。简单的C/S服务模式客户端和服务器采用的是一对一的关系,而实际上一个客户同时可以与多个服务器通信,一个服务器同时也能与多个客户通信。

    Linux下使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务器端和客户端两部分,如图1所示。76a0345e0be0eeaeb48e8b4592831612.png

    服务器端与客户端连接的步骤如下:

    1)使用socket0函数创建套接字;

    2)将创那的套接字绑定到指定的地址结构

    3)Listen0函数设置套接字为监听模式,使服务器进入被动打开的状态

    4)接受客户端的连接请求,建立连接

    5)终止连接

    客户端实现步骤:

    1)使用socket0函数创建套接字

    2)调用connect0函数建立一个TCP服务器的连接

    3)发送数据请求,接收服务器的数据应答

    4)终止连接

    这样就建立了最简单的C/S连接模式,而所有基于TCP套接字的网络服务也都是建立在这个基础上的。

    前面介绍了简单的TCP客户端/服务器概念和连接,其中服务器每次只能处理一个客户的请求,它的实现虽然很简单但效率却很低,在实际应用中,这样的服务器是不能满足实际需求的。

    在实际应用中为了让一个服务器同时为多个客户服务,处理多个客户的请求,那么就需要用并发服务器。Linux下主要支持的并发服务器有进程、线程。创建线程要比进程快,但一个进程内的所有线程共享相同的内存空间、全局变量等信息,所以当一个线程崩溃时,它会影响同一进程中的其他线程。

    Linux系统中可以同时存在多个进程,但相对线程来说,进程是独立的。它拥有独立的地址空间、执行堆栈、文件描述符等,在未经允许的情况下,一个进程不能访问另一个进程的资源,因此一个进程崩溃不会造成其他进程的崩溃。由于考虑远程监控系统要求的安全性和稳定性,本系统设计为多进程并发服务器。图2为并发服务器的基本模型图。cc08e5f40fb3c0919392838d9ce68654.png

    1.3 多进程服务器原理

    在多进程并发服务器中是通过调用fork或vfork函数来创建新进程。当父进程产生新的子进程后,父、子进程共享父进程在调用fork之前的所有描述符。接下来父进程只负责接收客户请求,而子进程只负责处理客户请求。

    图3说明父进程调用fork生成子进程后,父、子进程对客户请求和描述符的操作过程。6544639560e4fc46a9497ffc8d28fd1f.png

    1)当服务器调用accept0函数时,连接请求从客户到达服务器时双方状态。

    2)当客户的请求被接受后。接下来服务器就会调用fork函数生成子进程。

    3)最后父进程关闭已连接描述符,由子进程关闭监听描述符,这样既可以节省系统资源,又可以防止父、子进程同时对共享描述符进程操作。至此子进程处理与客户的连接,父进程可以对监听描述符再次调用accept,继续处理下一个客户的请求。

    2 功能代码分析

    网络主程序设计其实主要也就是父进程所执行的程序,程序设计的流程图如4所示。b2caaa9e58a1f616f003141ed1824fc0.png

    linux中的网络编程通过socket接口实现。socket既是一种特殊的I/O,它也是一种文件描述符。一个完整的socket包括协议、本地地址、本地端口、远程地址、远程端口;每一个socket有一个本地的唯一socket号,由操作系统自动分配。以下是建立TCP socket,其中AF_INET为IPv4,SOCK_STREAM为TCP协议,如建立失败则返回-1。

    listen_fd=socket(AF_INET,SOCK_STREAM,0)

    调用bzero初始化套接字地址结构,并对地址结构中的成员赋值,代码如下。

    bzero(client_addr,sizeof(struct sockaddr_in));

    client_addr.sin_family=AF_INET;

    client_addr.sin_port=htons(MY_PORT);

    client_addr.sin_addr.s_addr=htonl(INADDR_ANY);

    为了给调用socket0函数产生的套接字分配一个本地协议地址,建立地址与套接字的对应关系,就要用到绑定函数bind0。通过绑定后端口号保证了地址信息的唯一性。如失败返回-1。

    展开全文
  • 实现一个多进程并发服务器,可以实现多个客户端的连接。 把每个连接的客户端的ip和port输出,而且每个客户端的输入都在服务器输出 把客户端的小写转化为大写 声明:因个人能力有限,本文仅是个人的学习记录笔记,...
  • 其他关联文章@丶4ut15m:TCP网络编程(c)UDP网络编程(c)多线程并发服务器(c)IO复用(c)多进程并发服务器多进程并发服务器整个流程和单进程差别不太大,主要区别在交互部分.服务器->创建套接字->绑定地址结构->...
  • 并发服务器进程”基本概念程序:存放在磁盘文件中可执行文件。进程:程序的执行实例。它是一个动态实体,是独立的任务。“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个...
  • 在做网络服务的时候并发服务端程序的编写必不可少。前端客户端应用程序是否稳定一部分取决于客户端自身,而...本次主要讨论多进程并发服务器模型:使用多进程并发服务器时要考虑以下几点:父进程最大文件描述个数(父...
  • 内容简介本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握...并通过实例深入剖析并发服务器程序的开发流程、架构设计、运行原理、性能调优以及异步I/O模型、线程池、线程...
  • 并发性(concurrency):指在同一时刻只能有一条指令执行,但进程指令被快速轮换执行,使得在宏观上具有进程同时执行的效果。在操作系统中,安装了个程序,并发指的是在一段时间内宏观上有个程序同时运行...
  • 多进程在一台计算机系统中使用两个或多个CPU单元。 通过利用计算机系统中可用的全部CPU核心,这是最好的方法来充分利用我们的硬件。多线程这是CPU通过同时执行多个线程来管理操作系统使用的能力。 多线程的主要思想...
  • 多进程和多线程的服务器代码设计思路如下 2.程序代码 2.1 多进程服务器 #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <...
  • 1 python多进程编程概述 2 需求和方案 背景: 需求: 解决思路: 需要解决的问题和方案: 3 完整代码 1 python多进程编程概述 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源,在...
  • 1.程序、进程和线程 二进制程序(binaries)是指保存在存储介质上的程序,以给定操作系统和计算机体系结构可访问的格式编译生成,可以运行但尚未开始。...一个进程包含一个或个线程。如果一个进程只包含一个线程,则该
  • Linux网络编程使用多进程实现服务器并发访问发布时间:2013-10-30 09:33:48 作者:佚名 我要评论采用多进程的方式实现服务器并发访问的经典范例。采用多进程的方式实现服务器并发访问的经典范例。程序实现功能:...
  • 1.服务器处理并发的必要性 如下图所示, 当一个客户端与服务器建立...这个问题可以通过引入多线程和多进程来解决。服务端接受一个客户端的连接后,创建一个线程或者进程,然后在新创建的线程或进程中循环处理数据。主
  • 一 multiprocessing模块介绍python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。multiprocessing模块...
  • 具有代表性的并发服务器端实现模型和方法: 多进程服务器:通过创建多个进程提供服务 多路复用服务器:通过捆绑并同一管理I/O对象提供服务 多线程服务器:通过生成与客户端等量的线程提供服务 多进程服务器不适合...
  • Linux下PHP多进程编程

    2021-04-30 07:32:33
    本套课程是老师在互联网企业中打拼多年积累的技术开发经验录制而成。现在编程语言层出不穷,但它们的内部系统调用函数...它的内部调用机制,大家不但掌握了并发编程知识还能将所学知识运行到其它领域中如服务器并发...
  • 已有的事,后必再有;已行的事,后必再行。 UNIX网络编程,一往无前!...如果程序运行速度需要较时间服务每个客户,那么我们必须以某种方式重叠对各个用户的服务,即并发服务器并发服务器开始辽!
  • 十、多进程服务器

    2021-07-31 11:17:03
    至于什么是多进程,这里不展开叙述,可以去查阅相关技术资料,在本章中使用到的技术有:多线程编程以及信号处理,如果对这些技术不太熟悉可以自行查看相关资料。这里只介绍几个操作函数 一、相关操作函数 1. 创建...
  • 介绍:运行在ubuntu linux系统,需要先打开一个终端运行服务端代码,这时,可以打开个终端同时运行个客户端代码(注意客户端数目要小于MAX_FD);在客户端输入数据后回车,可以看见服务器收到数据,并回复客户端...
  • 本文实例分析了Python多进程服务器并发原理及用法。分享给大家供大家参考,具体如下:进程什么是进程进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。进程与程序的区别程序仅仅只是一堆代码而已...
  • 多线程和并发多线程和多进程多线程一定快吗学习并发的四个阶段一、你真的了解并发吗?为什么要使用并发?我们有没有见过并发的场景呢?其实并发是无处不在的,比如,淘宝的双十一就是一个非常高的并发量,就是很多人...
  • 多进程编程

    2021-03-10 14:55:17
    目录 1 服务器并发访问的问题 服务器按照处理方式可以分为迭代服务器和...Linux下有三种实现并发服务器的方式:多进程并发服务器、多线程并发服务器、IO复用,今天就是多进程并发服务器的实现。 2 多进程编程 (1)什

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 105,291
精华内容 42,116
关键字:

多进程并发服务器编程