Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)

简介: Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)

一、TCP服务器(一请求一线程) 的原理

通过sockfd绑定(bind)和监听(listen),每过来一个客户端就接受(accept),并创建一个clientfd,每个clientfd,占据一个线程。

每个线程执行 接受(recv)并printf的任务。

具体的监听过程

二、完整代码

#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
#define BUFFER_LENGTH 1024
void* client_routine(void* arg){
    int clientfd=*(int*)arg;
    while(1){
        char buffer[BUFFER_LENGTH]={0};
        int len=recv(clientfd,buffer,BUFFER_LENGTH,0);//阻塞就会挂起
        if(len<0){//阻塞io不存在len<0因为它会挂起在recv时刻,一旦发生,就说明出错了
            close(clientfd);
            break;
        }else if(len==0){//disconnect (读取数据为0就说明客户端断开连接了)
            close(clientfd);
            break;
        }else{
            printf("Recv:%s,%d bytes\n",buffer,len);
        }
    }
}
int main(int argc,char** argv){
    if(argc<2){
        printf("Param Error\n");
        return -1;
    }
    int port=atoi(argv[1]);
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    sockaddr_in addr;
    memset(&addr,0,sizeof(sockaddr_in));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(port);
    addr.sin_addr.s_addr=INADDR_ANY;//0.0.0.0 泛指本机的意思
    if(bind(sockfd,(sockaddr*)&addr,sizeof(sockaddr_in))<0){//绑定
        perror("bind");
        return 2;
    }
    if(listen(sockfd,5)<0){//监听(最多可以排队5个)
        perror("listen");
        return 3;
    }
    //一请求 一线程
    while(1){
        sockaddr_in client_addr;
        memset(&client_addr,0,sizeof(sockaddr_in));
        socklen_t client_len = sizeof(client_addr);
        int clientfd = accept(sockfd,(sockaddr*)&client_addr,&client_len);//接受一个客户,并将它的ip存到client_addr中,并形成了一个客户端fd
        pthread_t thread_id;
        pthread_create(&thread_id,NULL,client_routine,&clientfd);//为每个clientfd分配一个线程
    }
    return 0;
}

编译指令

g++ tcp_sever.cpp -o tcp_sever -lpthread

三、测试

执行,设置服务器端口为8888

./tcp_server 8888

打开NetAssist.exe

选择TCP Client,远程主机是自己的服务器的ip:端口号

点击连接

然后在下方可以发送数据了,点击发送

在服务器端可以接受到数据

四、补充

多个客户端,如何区分哪个客户端发送的?

sockfd是解决不了的

通过定义应用协议来解决,比如说在发送的同时也发送 用户id

一请求一线程 的缺点:

随着客户端越来越多 (比如100w)

不合适用一请求一线程的方式。

posix thread 8M。 1G内存 —》128个。比较有限。

现在已经弃用了,而选用epoll的方式


相关文章
|
25天前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
31 1
|
16天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
40 6
|
1月前
|
Linux 编译器 程序员
【Linux 调试秘籍】深入探索 C++:运行时获取堆栈信息和源代码行数的终极指南
【Linux 调试秘籍】深入探索 C++:运行时获取堆栈信息和源代码行数的终极指南
68 0
|
1月前
|
存储 算法 Java
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
74 0
|
1月前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
67 0
|
1月前
|
安全 Java 调度
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
【C/C++ 线程池设计思路 】设计与实现支持优先级任务的C++线程池 简要介绍
44 2
|
1月前
|
Linux API C++
【C++ 线程包裹类设计】跨平台C++线程包装类:属性设置与平台差异的全面探讨
【C++ 线程包裹类设计】跨平台C++线程包装类:属性设置与平台差异的全面探讨
51 2
|
1月前
|
设计模式 安全 C++
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
71 2
|
1月前
|
监控 Linux 编译器
Linux C++ 定时器任务接口深度解析: 从理论到实践
Linux C++ 定时器任务接口深度解析: 从理论到实践
70 2
|
1月前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
76 0