多进程并发服务器

多进程并发服务器实现

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <head.h>

#define PORT 8888             //1024~49151
#define IP "192.168.122.120" //ifconfig查看本机IP

int deal_cli_msg(int newfd, struct sockaddr_in cin);


void handler(int sig)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

int main(int argc, const char *argv[])
{
    //捕获17) SIGCHLD信号
    if(signal(17, handler) == SIG_ERR)
    {
        ERR_MSG("signal");
        return -1;
    }
    printf("捕获成功\n");


    //创建流式套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("sfd = %d\n", sfd);

    //设置允许端口被快速复用
    int reuse = 1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速重用成功\n");


    //填充地址信息结构体,真实的地址信息结构体根据地址族指定
    //AF_INET: man 7 ip
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;      //必须填AF_INET
    sin.sin_port        = htons(PORT);  //端口号:1024~49151
    sin.sin_addr.s_addr = inet_addr(IP); //本机IP ifconfig查看

    //绑定服务器的IP和端口--->必须绑定
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("bind success \n");

    //将套接字设置为被动监听状态
    if(listen(sfd, 128) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("listen success\n");

    struct sockaddr_in cin;     //存储客户端的地址信息
    socklen_t addrlen = sizeof(cin);
    int newfd = -1;

    pid_t cpid = 0;
    while(1)
    {
        //父进程只负责连接
        //从已完成连接的队列中获取一个客户端信息,生成一个新的文件描述符
        //该文件描述符才是与客户端通信的文件描述符
        newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
        if(newfd < 0)
        {
            ERR_MSG("accept");
            return -1;
        }
        printf("[%s : %d] newfd=%d 客户端连接成功\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);

        //能运行到当前位置,则代表有客户端连接成功,此时需要创建一个子进程,专门用于交互
        cpid = fork();
        if(0 == cpid)       //子进程中为真
        {
            close(sfd);         //子进程只负责交互,所以sfd对于子进程而言没有用
            deal_cli_msg(newfd, cin);
            exit(0);            //交互结束后,必须要退出子进程
        }

        close(newfd);       //父进程只负责连接,所以newfd对于父进程而言没有用
    }

    //关闭所有文件描述符
    close(sfd);

    return 0;
}


int deal_cli_msg(int newfd, struct sockaddr_in cin)
{
    char buf[128] = "";
    ssize_t res = 0;
    while(1)
    {
        bzero(buf, sizeof(buf));
        //接收数据
        res = recv(newfd, buf, sizeof(buf), 0);
        if(res < 0)
        {
            ERR_MSG("recv");
            return -1;
        }
        else if(0 == res)
        {
            printf("[%s : %d] newfd=%d 客户端下线\n", \
                    inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);                                  
            break;
        }

        printf("[%s : %d] newfd=%d : %s\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, buf);

        //发送数据
        strcat(buf, "*_*");
        if(send(newfd, buf, sizeof(buf), 0) < 0)
        {
            ERR_MSG("send");
            return -1;
        }
        printf("send success\n");
    }
    close(newfd);

    return 0;
}
                                                                                                        
相关推荐
济617几秒前
linux 系统移植(第五期)--Uboot移植(4)--在U-Boot 中添加自己的开发板(4) -其他需要修改的地方-- Ubuntu20.04
linux·运维·服务器
不知名XL17 分钟前
day24 贪心算法 part02
算法·贪心算法
老顾聊技术19 分钟前
“Anthropic 最新发布的 AI Skills:赋能任务自动化与跨领域应用“
运维·人工智能·自动化
AI科技星22 分钟前
时空几何:张祥前统一场论20核心公式深度总结
人工智能·线性代数·算法·机器学习·生活
令狐少侠201126 分钟前
Linux 系统部署夜莺 nightingale 监控公司的watchdog
linux·运维·服务器
菜鸟233号27 分钟前
力扣518 零钱兑换II java实现
java·数据结构·算法·leetcode·动态规划
kkce1 小时前
域名CDN检测意义
服务器·前端·网络
咋吃都不胖lyh1 小时前
Haversine 距离算法详解(零基础友好版)
线性代数·算法·机器学习
百度Geek说1 小时前
百度流式计算开发平台的降本增效之路
运维·云原生
FPGA小c鸡1 小时前
FPGA通信基带算法完全指南:从理论到实战的DSP加速方案
算法·fpga开发