简单TCP网络程序(多进程及多线程版本)

我们之前实现了的TCP交互版本,只能实现一台服务器当前只能服务一个客户,是单进程的。
https://blog.csdn.net/ZWE7616175/article/details/80260420

为了解决这一问题,我们实现多进程和多线程的版本。

多进程版本

服务器端

#include <stdio.h>                  
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void ProcessRequest(int new_sock, struct sockaddr_in* peer)
{
     char buf[1024];
     buf[0]='\0';
     while(1)
     {
         ssize_t s = read(new_sock, buf, sizeof(buf));
         if(s > 0)
         {
             buf[s]='\0';
             printf("[%s:%d] %s",inet_ntoa(peer->sin_addr),\
                     ntohs(peer->sin_port),buf);
         }
         else
         {
             printf("client quit\n");
             break;
         }
         write(new_sock,buf,strlen(buf)+1);
     }
}                                                                                                                        
void CreateWorker(int new_sock,struct sockaddr_in* peer)
{
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork");
        return;
    }
    else if(pid == 0)
    {
        //子进程
        if(fork() == 0)
            //孙子进程
            ProcessRequest(new_sock, peer);//孙子进程为孤儿进程,系统回收
        exit(0);//子进程退出
    }
    else//父进程
    {
        close(new_sock);
        waitpid(pid, NULL, 0);//父进程回收子进程
    }

//服务器
int main(int argc, char* argv[])
{
    if(argc!=3){
        printf("Usage %s is port\n",argv[0]);
        return 1;
    }

    //创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0){
        perror("socket");
        return 2;
    }

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[2]));
    local.sin_addr.s_addr = inet_addr(argv[1]);

    //绑定
    if(bind(sock, (struct sockaddr*)&local, sizeof(local))<0)
    {
        perror("bind");
    return 3;
    }

    //监听
    if(listen(sock, 5)<0)
    {
        perror("listen");
        return 4;
    }


    while(1)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);

        //接受请求
        int new_sock=accept(sock, (struct sockaddr*)&peer,&len);
        if(new_sock<0)
        {
            perror("accept");
            return 5;
        }
        CreateWorker(new_sock, &peer);
    }
        return 0;
}

运行服务器端。
这里写图片描述
打开多个客户端,此处我们只测试两个。
这里写图片描述
这里写图片描述
多进程服务器

缺点:

1.只有链接来了才创建进程,影响性能。(类似于我们生活中的例子,到了饭店了老板才开始买菜),解决这一问题,可以提前创建,进程池的引入。
2.能够同时服务量有限,因为每个进程都需要分配资源。
3.进程增多导致切换增多,调度周期增长,进而影响性能。

优点:

1.可以同时服务多个客户。
2.易于编写。
3.稳定,任意一个进程挂掉,不会影响其他进程。

多线程版本

服务器:

#include <stdio.h>                         
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef struct Arg
{
    int fd;
    struct sockaddr_in addr;
}Arg;

void ProcessRequest(int new_sock, struct sockaddr_in* peer)
{
   char buf[1024];
   buf[0]='\0';
   while(1)
   {
       ssize_t s = read(new_sock, buf, sizeof(buf));
       if(s > 0)
       {
           buf[s]='\0';
           printf("[%s:%d] %s",inet_ntoa(peer->sin_addr),\
                   ntohs(peer->sin_port),buf);
       }
       else
       {
           printf("client quit\n");
           break;
       }
       write(new_sock,buf,strlen(buf)+1);
   }
}

void* CreateWorker(void* ptr)
{
    Arg* arg = (Arg*)ptr;
    ProcessRequest(arg->fd, &arg->addr);
    free(arg);
    return NULL;
}

//服务器
int main(int argc, char* argv[])
{
    if(argc!=3){
        printf("Usage %s is port\n",argv[0]);
        return 1;
    }

    //创建套接字                
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0){
        perror("socket");
        return 2;
    }

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[2]));
    local.sin_addr.s_addr = inet_addr(argv[1]);

    //绑定
    if(bind(sock, (struct sockaddr*)&local, sizeof(local))<0)
    {
        perror("bind");
        return 3;
    }

    //监听
    if(listen(sock, 5)<0)
    {
        perror("listen");
        return 4;
    }


    while(1)           
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);

        //接受请求
        int new_sock=accept(sock, (struct sockaddr*)&peer,&len);
        if(new_sock<0)
        {
            perror("accept");
            return 5;
        }
        pthread_t tid = 0;
        Arg* arg = (Arg*)malloc(sizeof(Arg));
        arg->fd = new_sock;
        arg->addr = peer;
        pthread_create(&tid, NULL, CreateWorker, (void*)arg);
        pthread_detach(tid);

    }
        return 0;
}

运行服务器端。
这里写图片描述
打开两个终端测试。
这里写图片描述
这里写图片描述
多线程版本缓解了多进程的性能问题和资源问题,但只是多进程的一个缓解。也存在着一些缺点:相比多进程来说,不稳定,任意一个线程挂掉,所有的线程都会退出,并且共享资源,有风险。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值