多线程并发服务器

网络服务器模型简介

在这里插入图片描述
网络服务器 常用于对后端提供网络功能,逻辑处理,数据处理的程序或者架构等;服务器常伴随着数据高连接数高吞吐量的环境中,所以对数据的及时处理的要求很高;在网络服务器模型中常见的模型有:循环服务器和并发服务器;


循环服务器

在这里插入图片描述
服务器依次处理每个客户端发送过来的数据,直到当前客户端的所有请求处理完成再处理下一个客户端;当服务器接收到大量的数据时,会因为服务器处理能力不足而导致客户端响应过慢;


并发服务器

在这里插入图片描述
创建多进程/多线程处理机制,分别为每一个客户端创建一个任务来处理,可以极大的提高服务器的并发处理能力;


TCP网络编程相关API接口图接

在这里插入图片描述


并发服务器服程序(TCP)

并发服务器的优势很明显的体现了出来,下面为 利用多线程实现并发服务器的代码片.

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


//创建的线程只负责接受数据
void * message_handling(void * arg)
{
    int cfd = *(int *)arg;
    while (1)
    {
        char buf[255] = {0};

        int state = -1;

        //接收客户端发送的数据
        state = recv(cfd,buf,sizeof(buf),0);
        if (-1 == state)
        {
            perror("子进程客户 读取数据失败");
            break;

        }else if (0 == state)
        {
            perror("子进程客户端已退出连接");
            break;
        }

        printf("%s\n",buf);
    }

    pthread_exit(NULL);

}



int main(int argc,const char * argv[])
{   
    if (argc < 3)
    {
        perror("输入参数错误\n");
        return -1;
    }

    //建立套接字
    int sfd = -1;
    sfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sfd)
    {
        perror("套接字创建失败");
        return -1;
    }

    //绑定 服务器 IP地址与端口号
    struct sockaddr_in svr;

    svr.sin_family = AF_INET;                   //IPV4
    svr.sin_addr.s_addr = inet_addr(argv[1]);   //ip地址
    svr.sin_port = htons(atoi(argv[2]));        //端口号

    //将套接字文件描述符、(服务器)端口号和ip绑定到一起
    if (0 > bind(sfd,(const struct sockaddr *)&svr,sizeof(svr)))
    {
        perror("服务器数据绑定失败");
        return -1;
    }

    //建立监听队列,让套接字进入到被动监听状态
    if (-1 == listen(sfd,10))
    {
        perror("建立监听队列失败");
        return -1;
    }

    
    int cfd = -1;
    while (1)
    {
        //阻塞等待TCP连接(三次握手)
        printf("主进程等待连接中...\n");

        //向该主机发送方的IP
        struct sockaddr_in ip;

        //向该主机发送方的端口
        socklen_t len = sizeof(ip);

        //接受连接,产生新的套接字
        cfd = accept(sfd,(struct sockaddr *)&ip,&len);
        if (-1 == cfd)
        {
            perror("新的套接字产生失败\n");
            return -1;
        }

        //创建线程 -----------------------------------------------
        pthread_t TID = 0;//用于存放子线程的ID号
        int ERROE = 0;    //用于存放错误码

        printf("主线程 cfd %d\n",cfd);

        //创建子线程,将文件描述符号加入形参
        ERROE = pthread_create(&TID,NULL,(void *)message_handling,(void *)&cfd);
        if (ERROE != 0)
        {
            //将获取到的错误码赋值给错误码变量
            errno = ERROE;
            perror("子线程创建失败");
            return -1;
        }

        //将组合式线程转换为分离式线程
        pthread_detach(TID);

        char * Receiving_IP = inet_ntoa(ip.sin_addr);   //将获取到的ip(网络字节序)转换为字符串 
        int Receiving_port = ntohs(ip.sin_port);        //将获取到的端口(网络字节序)转换为十进制数
        //printf("\n<<<================================================\n");
        printf("\t客户端成功连接服务器\n\n");
        printf("\t客户端IP\t:%s\n",Receiving_IP);
        printf("\t客户端端口\t:%d\n",Receiving_port);
        printf("\t线程TID号\t:%ld\n",TID);
        printf("================================================>>>\n\n");

    }

    return 0;
}




程序最终效果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值