6.10linux多进程并发服务器

titledatecommentscategoriestagspermalink
linux多进程并发服务器
2020/3/17
true
linux
linux
服务器
6.10

并发程服务器概念

一图胜前言,如下图是一般服务器并发服务示意图

并发服务器

多进程并发服务器

多进程服务器,顾名思义就是服务端会有多个进程提供网络服务。

开发多进程并发服务器需要注意以下几点:

  • 需要注意父进程最大文件描述个数(父进程中需要close关闭accept返回的网络文件描述符)
  • 系统内创建的进程个数(与内存大小相关)
  • 进程过多是否会降低整体服务器的性能——进程的切换(调度)本身也需要系统资源

多进程并发服务器示例

多进程并发服务器server

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"

/* waitpid 函数详解
原型: pid_t waitpid(pid_t pid, int *status, int options);
pid:
    pid>0    只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
    pid=-1    等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
    pid=0时   等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
    pid<-1    等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

status: 如果不是一个空指针,则终止进程的终止状态就存放在status所指向的单元。参数status如果是一个空指针,则表示父进程不关心子进程的终止状态

option:
    WNOHANG    若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0
    WUNTRACED    返回终止子进程信息和因信号停止的子进程信息
    WCONTINUED    返回收到SIGCONT信号而恢复执行的已停止子进程状态信息

返回值:
    成功    成功结束运行的子进程的进程号
    失败    返回-1
    WNOHANG    没有子进程退出返回0
*/
/*  fork()方法说明
    fork系统调用用于创建一个新进程,称为子进程,它与进行fork()调用的进程(父进程)并发运行。
    创建新的子进程后,两个进程都将执行fork()系统调用之后的下一条指令。子进程使用相同的PC(程序计数器),
    相同的CPU寄存器,相同的打开文件,这些文件在父进程中使用。fork()在子进程中返回0,向父进程返回正整数。
    实质是内部调用了copy_process拷贝父进程的PCB
*/
#define MAXLINE 80
#define SERV_PORT 800

void do_sigchild(int num)
{
    while (waitpid(0, NULL, WNOHANG) > 0);
}
int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    int i, n;
    pid_t pid;

    struct sigaction newact;
    newact.sa_handler = do_sigchild;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    sigaction(SIGCHLD, &newact, NULL);

    //指定为TCP连接,SOCK_STREAM
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    Listen(listenfd, 20);

    printf("Accepting connections ...\n");
    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

        pid = fork();//fork出子进程
        if (pid == 0) {//子进程
            Close(listenfd);
            while (1) {
                n = Read(connfd, buf, MAXLINE);
                if (n == 0) {
                    printf("the other side has been closed.\n");
                    break;
                }
                printf("received from %s at PORT %d\n",
                        inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                        ntohs(cliaddr.sin_port));
                for (i = 0; i < n; i++)
                    buf[i] = toupper(buf[i]);
                Write(connfd, buf, n);//小写转大写发回去
            }
            Close(connfd);
            return 0;
        } else if (pid > 0) {//父进程
            Close(connfd);
        } else
            perr_exit("fork");
    }
    Close(listenfd);
    return 0;
}

以上就是一个简单的多进程服务器

客户端示例代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 6666

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (fgets(buf, MAXLINE, stdin) != NULL) {
        Write(sockfd, buf, strlen(buf));//接收键盘输入发送到服务器端
        n = Read(sockfd, buf, MAXLINE);
        if (n == 0) {
            printf("the other side has been closed.\n");
            break;
        } else
            Write(STDOUT_FILENO, buf, n);
    }
    Close(sockfd);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值