linux服务器端多进程代码—服务器/客户端一对多

一、多进程服务器代码

#include
#include
#include
#include<string.h>
#include           /* See NOTES */
#include 
#include 
#include 
#include
#include

void reclye()//进程回收函数
{
    pid_t pid;
    while((pid=waitpid(-1,NULL,WNOHANG))>0)//-1表示回收任意子进程;NULL表示不关心子进程的状态;WNOHANG表示如果当前没有子进程退出会立即返回,如果有子进程退出则返回退出的id,
    {
        printf("child died,pid=%d\n",pid);
    }
}

int main(int argc,const char* argv[])
{
    if(argc<2)
    {
        printf("eg:./a.out port\n");
        return -1;
    }
    int port=atoi(argv[1]);//argv[1],从命令行输入端口号
    //1、创建socket套接字,bind绑定,listen监听
    int lfd=socket(AF_INET,SOCK_STREAM,0);//AF_INET表示ipv4协议,SOCK_STRRAM表示使用TCP协议,0表示使用对应类型的默认协议
    if(lfd==-1)//socket创建套接字失败返回-1,并且设置errno,出现错误的时候系统会自动检测错误类型并将错误信息打印到命令行,下述代码同理
    {
        printf("socket err");
        return -1;
    }

    //bind
    struct sockaddr_in ser_addr;//创建结构体存储服务器ip地址、端口号
    ser_addr.sin_family=AF_INET;//ipv4协议
    ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);//htonl函数将ip地址从本机字节顺序转换到网络字节顺序(l表示无符号长整型),INADDR_ANY表示本机任意可用IP
    ser_addr.sin_port=htons(port);//htons函数将端口号从本机字节顺序转换到网络字节顺序(s表示无符号短整型)
    int ret=bind(lfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
    if(ret==-1)
    {
        printf("bind error");
        return -1;
    }

    //listen
    listen(lfd,128);

    //使用信号回收子进程
    struct sigaction act;//创建捕捉信号的结构体
    act.sa_flags=0;//一般赋值为0
    act.sa_handler=reclye;//函数指针指向被调用函数,执行捕捉函数的时候调用该函数
    sigemptyset(&act.sa_mask);//清空信号集
    sigaction(SIGCHLD,&act,NULL);//子进程在暂停或退出的时候会发送SIGCHLD信号

    //2、循环等待接收客户端连接--accept,如果有连接创建子进程
    struct sockaddr_in cli_addr;
    socklen_t cli_addr_len=sizeof(cli_addr);
    while(1)
    {
        //父进程接收连接请求
        //accept阻塞的时候被信号中断,处理信号对应的操作之后
        //回来之后不阻塞了,直接返回-1,这个时候errno被设置为EINTR
        int cfd=accept(lfd,(struct sockaddr*)&cli_addr,&cli_addr_len);
        while(cfd==-1&&errno==EINTR)
        {
            cfd=accept(lfd,(struct sockaddr*)&cli_addr,&cli_addr_len);
        }

        //
        char ip[16];
        memset(ip,0,sizeof(ip));
        const char* addr_dst=inet_ntop(AF_INET,&cli_addr.sin_addr.s_addr,ip,sizeof(ip));//将客户端IP转换为字符串形式存储到ip中
        printf("client IP:%s,port:%d,connect sucessful\n",addr_dst,ntohs(cli_addr.sin_port));//将端口号从网络字节顺序转换到本机字节顺序(无符号短整型)

        pid_t pid=fork();
        if(pid==0)//子进程
        {
            close(lfd);
            char buf[1024];
            while(1)//使用cfd文件描述符通信
            {
                //接收数据
                memset(buf,0,sizeof(buf));
                int len=read(cfd,buf,sizeof(buf));
                if(len<0)
                {
                    printf("read error");
                    exit(1);
                }else if(len==0)
                {
                    printf("IP:%s,客户端断开了连接\n",addr_dst);
                    close(cfd);
                    break;
                }
                printf("IP:%s,recv buf:%s\n",addr_dst,buf);

                //发送数据,将接收到的数据发送给客户端
                write(cfd,buf,sizeof(buf));
            }
            exit(1);//子进程退出
        }
        else if(pid>0)
        {
            //wait();不能等待回收,因为wait/waitpid都会阻塞,所以应该用信号回收子进程
            close(cfd);
        }

    }

    return 0;
}

二、运行截图

1、服务器端运行截图

linux服务器端多进程代码---服务器/客户端一对多

2、客户端A、B运行截图

linux服务器端多进程代码---服务器/客户端一对多

linux服务器端多进程代码---服务器/客户端一对多

注:nc命令可用模拟客户端测试,nc+ip+端口号

为了测试方便,仅模拟了两个客户端同时连接服务器,也可用同时多个客户端连接服务器

一入编程深似海,多学多查多动手

undefined

Original: https://www.cnblogs.com/asdzy/p/14328013.html
Author: 阿斯顿之意
Title: linux服务器端多进程代码—服务器/客户端一对多

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/587991/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球