如何实现一请求一线程式的tcp服务器
一.现有两台主机,分为服务器和客户端,服务器同客户端如何在网络中建立通信
本文仅描述服务端操作
1.创建一个流式套接字,绑定设定好的ip地址与端口
int sockfd = socket(AF_INET, SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(-1 == bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr))){
perror("bind error\n");
return -1;
}
2.监听这个端口,并且创建好用于记录客户端ip地址和端口的变量
listen(sockfd, 10);
INFO ("listen finished\n");
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
3.建立tcp连接同时创建新的套接字,用于后续的IO操作
INFO("accepting...\n");
int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&len);
INFO("accept finished\n");

4.用recv函数将从客户端传如buffer中,并将接收到的数据传回,用于检测连接是否为双工
char buffer[1024]={0};
int count = recv(clientfd,buffer,1024,0);
INFO("recv:%s,%d byte(s)\n",buffer,count);
count = send(clientfd,buffer,count,0);
INFO("SEND:%d\n",count);
至此,我们已经建立了服务端和客户端的tcp连接,并且能够实现双方的通信.
但问题来了,目前我们的tcp服务器仅能接受一个客户端发送的信息,并且每个客户端仅能发送一条消息。
TCP服务器如何和多个客户端形成稳定双工连接
很自然的想到,给建立新连接,并实现通信的过程,用一个while循环包住,这样就能不断创建新的连接。
while(1){
INFO("accepting...\n");
int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&len);
INFO("accept finished\n");
char buffer[1024]={0};
int count = recv(clientfd,buffer,1024,0);
INFO("recv:%s,%d byte(s)\n",buffer,count);
count = send(clientfd,buffer,count,0);
INFO("SEND:%d\n",count);
}
在改进完的基础上我们测试一个场景,用网络调试助手模拟三台客户端,从左到右编号1,2,3

我们按照编号顺序启动对tcp服务器的连接,下图是此时终端显示仅建立一条连接

接着我们分别发送客户端2、3号的数据,此时终端显示并未接受到任何数据

这时候我们传送客户端1的数据,数据按照连接建立的顺序实现被接收

梳理代码,如果我们只用while循环实现多连接,建立顺序靠后的连接,会由于顺序靠前连接未发送数据而被recv函数堵塞住,相互之间互相影响,这显然不是我们想要的效果。
所以选择我们创建一个线程,将收发数据放进子线程中执行
//主程序
pthread_t thid;
pthread_create(&thid,NULL,ClientThread,&clientfd);
//子线程
void *ClientThread(void *arg){
int clientfd = *(int*)arg;
char buffer[1024]={0};
int count = recv(clientfd,buffer,1024,0);
INFO("recv:%s,%d byte(s)\n",buffer,count);
count = send(clientfd,buffer,count,0);
INFO("SEND:%d\n",count);
}
但现在还有一个问题,目前的所有连接只能相互通信一次,为了实现长连接,我们将子线程的收发数据操作放入while循环中
while(1){
char buffer[1024]={0};
int count = recv(clientfd,buffer,1024,0);
INFO("recv:%s,%d byte(s)\n",buffer,count);
count = send(clientfd,buffer,count,0);
INFO("SEND:%d\n",count);
}
}
至此,我们实现了一请求一线程式的tcp服务器。