Linux网络多进程并发服务器和多线程并发服务器

多进程

还是以大小写转换为例子

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "wrap.h"
#include <ctype.h>
#include <signal.h>
#include <sys/wait.h>

#define SERV_PORT 9527

void catch_child(int signum)//信号,用来回收子进程
{
    while((waitpid(0,NULL,WNOHANG)) > 0);
    return;
}

int main(int argc,char* argv[])
{
    int lfd,cfd;
    int ret,i;
    char buf[BUFSIZ],client_IP[1024];
    pid_t pid;
    struct sockaddr_in serv_addr,clit_addr;
    socklen_t clit_addr_len;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
    lfd = Socket(AF_INET,SOCK_STREAM,0);
    Bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    Listen(lfd,128);
    
    clit_addr_len = sizeof(clit_addr);
    while(1)
    {
        cfd =  Accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
        pid = fork();//创建子进程
        if(pid < 0)
        {
            perr_exit("fork error");
        }
        else if(pid == 0)
        {
            printf("client ip:%s port%d\n",
                inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
                ntohs(clit_addr.sin_port));//打印客户端网络信息
            close(lfd);
            break;
        }
        else
        {
        	//父进程调用信号回收子进程
            struct sigaction act;
            act.sa_handler = catch_child;
            sigemptyset(&act.sa_mask);
            act.sa_flags = 0;
            
            ret = sigaction(SIGCHLD,&act,NULL);
            if(ret != 0)
            {
                perr_exit("signal error");
            }
            close(cfd);
            continue;
        }
    }
    
    if(pid == 0)//大小写转换
    {
        for(;;)
        {
            
            ret = read(cfd,buf,sizeof(buf));
            if(ret == 0)
            {
                close(cfd);
                exit(1);
            }
             for(i = 0;i < ret;i++)
            {
                 buf[i] = toupper(buf[i]);
            }       
            write(cfd,buf,ret);
    
            write(STDOUT_FILENO,buf,ret);
        }
    }
    return 0;
}

多线程

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info {                     //定义一个结构体, 将地址结构跟cfd捆绑
    struct sockaddr_in cliaddr;
    int connfd;
};

void *do_work(void *arg)
{
    int n,i;
    struct s_info *ts = (struct s_info*)arg;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看

    while (1) {
        n = Read(ts->connfd, buf, MAXLINE);                     //读客户端
        if (n == 0) {
            printf("the client %d closed...\n", ts->connfd);
            break;                                              //跳出循环,关闭cfd
        }
        printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
                ntohs((*ts).cliaddr.sin_port));                 //打印客户端信息(IP/PORT)

        for (i = 0; i < n; i++) 
            buf[i] = toupper(buf[i]);                           //小写-->大写

        Write(STDOUT_FILENO, buf, n);                           //写出至屏幕
        Write(ts->connfd, buf, n);                              //回写给客户端
    }
    Close(ts->connfd);

    return (void *)0;
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    pthread_t tid;

    struct s_info ts[256];      //创建结构体数组.
    int i = 0;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd

    bzero(&servaddr, sizeof(servaddr));                             //地址结构清零
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                               //指定本地任意IP
    servaddr.sin_port = htons(SERV_PORT);                                       //指定端口号 

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

    Listen(listenfd, 128);                                                      //设置同一时刻链接服务器上限数

    printf("Accepting client connect ...\n");

    while (1) {
        cliaddr_len = sizeof(cliaddr);
        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求
        ts[i].cliaddr = cliaddr;
        ts[i].connfd = connfd;

        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
        pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.
        i++;
    }

    return 0;
}
相关推荐
律宏阔1 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔1 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴1 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千1 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei371 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei371 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei371 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
GeW2 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
百万蹄蹄向前冲2 小时前
双端同步!云服务器装最新Node.js v26.10全过程追踪
服务器·人工智能·node.js
GeW2 小时前
工业场景中的Linux与数据库选型:高端化转型的技术底座
linux