C/S架构学习之多线程实现TCP并发服务器

这篇具有很好参考价值的文章主要介绍了C/S架构学习之多线程实现TCP并发服务器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 并发概念:
  • 并发是指两个或多个事件在同一时间间隔发生;
  • 多线程实现TCP并发服务器的实现流程:
  • 一、创建套接字(socket函数):
  • 通信域选择IPV4网络协议、套接字类型选择流式;
	int sockfd = socket(AF_INET,SOCK_STREAM,0); //通信域选择IPV4、套接字类型选择流式
  • 二、填充服务器的网络信息结构体:
  • 1.定义网络信息结构体变量;
  • 2.求出结构体变量的内存空间大小;
  • 3.结构体清零;
  • 4.使用IPV4网络协议;
  • 5.预留给在终端输入的IP地址;
  • 6.预留给在终端输入的网络字节序的端口号;
	struct sockaddr_in serveraddr; //定义网络信息结构体变量
    socklen_t serveraddrlen = sizeof(serveraddr);//求出结构体变量的内存空间大小

    memset(&serveraddr,0,serveraddrlen); //结构体清零

    serveraddr.sin_family = AF_INET;  //使用IPV4网络协议
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);  //IP地址
    serveraddr.sin_port = htons(atoi(argv[2]));//网络字节序的端口号
  • 三、套接字和服务器的网络信息结构体进行绑定(bind函数):
	int ret = bind(sockfd,(struct sockaddr *)&serveraddr,serveraddrlen);
  • 四、套接字设置成被动监听(listen函数):
	int ret1 = listen(sockfd, 5);
  • 五、阻塞等待客户端的连接(accept函数):
		if(-1 == (info.accept_fd = accept(sockfd,(struct sockaddr *)&(info.clientaddr),&clientaddr_len)))
        {
            perror("accept error");
            exit(-1);
        }
  • 六、若有客户端连接成功,就创建线程,专门用来和该客户端通信(pthread_create函数):
		if(0 != (ret1 = pthread_create(&thread_id,NULL,message_handling,&info)))
        {
            printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret1,strerror(ret1));
            exit(EXIT_FAILURE);
        }
  • 七、将线程设置成分离属性,线程结束后由操作系统回收资源(pthread_detach函数):
        if(0 != (ret2 = pthread_detach(thread_id)))
        {
            printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret2,strerror(ret2));
            exit(EXIT_FAILURE);
        }

  • 八、创建线程处理函数用来接收来自客户端的数据(recv函数)和给客户端发送应答消息(send函数):
	//线程处理函数
	void *message_handling(void *arg);
	
	int nbytes = recv(acceptfd,buf,sizeof(buf),0);
	printf("客户端发来数据[%s]\n",buf);
	
	strcat(buf,"----k"); //组装应答消息
	int ret2 = send(acceptfd,buf,sizeof(buf),0);
  • 九、退出线程(pthread_exit函数)和关闭套接字(close函数):
	close(info.accept_fd);
    pthread_exit(NULL);
  • 综合应用实例代码如下所示:
//多线程实现TCP并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdbool.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

typedef struct INFO
{
    int accept_fd;

    struct sockaddr_in clientaddr;

}info_t;

//线程处理函数
void *message_handling(void *arg);

int main(int argc, char const *argv[])
{
    //入参合理性检查
    if(3 != argc)
    {
        printf("Usage : %s <IP> <PORT>\n",argv[0]);
        exit(-1);
    }
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket error");
        exit(-1);
    }
    //填充服务器网络信息结构体
    struct sockaddr_in serveraddr;
    socklen_t serveraddr_len = sizeof(serveraddr);
    memset(&serveraddr,0,serveraddr_len);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    //将套接字与服务器网络信息结构体绑定
    if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,serveraddr_len))
    {
        perror("bind error");
        exit(-1);
    }

    //将套接字设置成被监听状态
    if(-1 == listen(sockfd,5))
    {
        perror("listen error");
        exit(-1);
    }

    info_t info;
    pthread_t thread_id;
    int ret1 = 0;
    int ret2 = 0;
    socklen_t clientaddr_len = sizeof(info.clientaddr);

    while(true)
    {
        
        //等待客户端连接
        if(-1 == (info.accept_fd = accept(sockfd,(struct sockaddr *)&(info.clientaddr),&clientaddr_len)))
        {
            perror("accept error");
            exit(-1);
        }
        //若有客户端连接成功,就创建线程,专门用来和该客户端通信
        if(0 != (ret1 = pthread_create(&thread_id,NULL,message_handling,&info)))
        {
            printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret1,strerror(ret1));
            exit(EXIT_FAILURE);
        }

        //将线程设置成分离属性,线程结束后由操作系统回收资源
        if(0 != (ret2 = pthread_detach(thread_id)))
        {
            printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret2,strerror(ret2));
            exit(EXIT_FAILURE);
        }

    }

    close(sockfd);
    

    return 0;
}

void *message_handling(void *arg)
{
    info_t info = *(info_t *)arg;

    printf("客户端[%s : %d]连接到服务器\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));

    //接收客户端数据,并作出应答

    int nbytes = 0;

    char buf[128] = {0};

    while(true)
    {
        memset(buf,0,sizeof(buf));
        //接收消息
        if(-1 == (nbytes = recv(info.accept_fd,buf,sizeof(buf),0)))
        {
            perror("recv error");
            break;

        }else if(0 == nbytes){

            printf("客户端[%s : %d]断开了连接\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));
            break;

        }
        if(!strcmp(buf,"quit"))
        {
            printf("客户端[%s : %d]退出了\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));
            break;
        }
        printf("客户端[%s : %d]发来消息[%s]\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port),buf);

        //组装应答
        strcat(buf,"------k");
        //发送应答
        if(-1 == send(info.accept_fd,buf,sizeof(buf),0))
        {
            perror("send error");
            break;
        }
    }

    close(info.accept_fd);
    pthread_exit(NULL);
    
}
  • 本示例代码,仅供参考;

文章来源地址https://www.toymoban.com/news/detail-734886.html

到了这里,关于C/S架构学习之多线程实现TCP并发服务器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于多线程实现服务器并发

    看大丙老师的B站视频总结的笔记 19-基于多线程实现服务器并发分析_哔哩哔哩_bilibili https://www.bilibili.com/video/BV1F64y1U7A2/?p=19spm_id_from=pageDrivervd_source=a934d7fc6f47698a29dac90a922ba5a3 思路:首先accept是有一个线程的,另外只要这个accept成功的和一个客户端建立了连接,那么我们就需要创

    2024年02月14日
    浏览(36)
  • 使用select实现TCP并发服务器模型

    本期主要分享的是对于select的使用,使用select实现TCP并发服务器模型,由于之前所用到的技术知识只能够支撑我们进行单个访问,但是有了select之后呢,我们就能够实现多用户进行访问;这也是非常符合客观需求的; 这次呢我们重点来使用一下select; 用到的头文件如下: 我

    2024年02月08日
    浏览(47)
  • 【高并发网络通信架构】2.引入多线程实现多客户端连接的tcp服务端

    目录 一,往期文章 二,代码实现 关键代码 完整代码 运行效果 【高并发网络通信架构】1.Linux下实现单客户连接的tcp服务端 因为accept是阻塞等待客户端连接,当客户端连接成功后才会执行accept后面的代码,所以为实现多个客户端连接,第一步是将accept放在master循环里。 rec

    2024年02月13日
    浏览(47)
  • 分别通过select、多进程、多线程实现一个并发服务器

    多进程 多线程 select

    2024年02月20日
    浏览(38)
  • TCP服务器的演变过程:揭秘使用多线程实现一对多的TCP服务器

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。本节在上一章节的基础上,添加多线程,为每个新接入的客户端分配线程,实现一个服务器程序处理多

    2024年02月04日
    浏览(58)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(81)
  • TCP服务器实现—多进程版,多线程版,线程池版

    目录 前言 1.存在的问题 2.多进程版 3.多线程版 4.线程池版 总结         在上一篇文章中使用TCP协议实现了一个简单的服务器,可以用来服务端和客户端通信,但是之前的服务器存在一个问题,就是当有多个客户端连接服务器的时候,服务器只能和一个客户端通信,其它的客

    2024年02月12日
    浏览(47)
  • TCP高并发服务器简介(select、poll、epoll实现与区别)

    一、创建套接字(socket函数): 二、填充服务器的网络信息结构体: 三、套接字和服务器的网络信息结构体进行绑定(bind函数): 四、套接字设置成被动监听(listen函数): 五、创建要监听的文件描述符集合: 使用select函数后,会将 没有就绪的文件描述符 在集合中 去除

    2024年01月19日
    浏览(55)
  • 【Linux后端服务器开发】封装线程池实现TCP多线程通信

    目录 一、线程池模块 Thread.h LockGuard.h ThreadPool.h 二、任务模块模块 Task.h 三、日志模块 Log.h 四、守护进程模块 Deamon.h  五、TCP通信模块 Server.h Client.h server.cpp client.cpp 关于TCP通信协议的封装,此篇博客有详述: 【Linux后端服务器开发】TCP通信设计_命运on-9的博客-CSDN博客 线程池

    2024年02月16日
    浏览(45)
  • 【Linux网络编程】TCP并发服务器的实现(IO多路复用select)

    服务器模型主要分为两种, 循环服务器 和 并发服务器 。 循环服务器 : 在同一时间只能处理一个客户端的请求。 并发服务器 : 在同一时间内能同时处理多个客户端的请求。 TCP的服务器默认的就是一个循环服务器,原因是有两个阻塞 accept函数 和recv函数 之间会相互影响。

    2024年02月03日
    浏览(82)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包