linux——TCP多线程并发服务器

多线程服务器 = 可以同时处理多个客户端

旧版:一次只能接一个客户,客户不走,别人连不进来。

新版:来一个客户,创建一个线程专门服务,同时支持 N 个客户端!

主函数加了一个while(1)循环

复制代码
pthread_t tid;

	int newfd = -1;
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	while(1)
	{
		newfd = accept(fd,(struct sockaddr *)&cin,&addrlen);
		if(newfd < 0)
		{
			perror("accept");
			exit(1);
		}

		char ipv4_addr[16];
		if(!inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
		{
			perror("inet_ntop");
			exit(1);
		}
		printf("Client:(%s,%d) is connect\n",ipv4_addr,ntohs(cin.sin_port));

		pthread_create(&tid,NULL,client_data_handle,(void *)&newfd);
	}

就是无线循环accept函数

accept 接到一个客户 → 立刻创建一个线程去服务它 → 主线程马上回去继续等下一个客户!

创建线程

复制代码
pthread_create(&tid, NULL, client_data_handle, (void *)&newfd);

让这个线程去执行 client_data_handle 函数专门服务当前这个客户端

主线程马上回去继续 accept 等下一个客户!

线程函数用来接收数据代码

复制代码
void* client_data_handle(void* arg)
{
	int newfd = *(int *)arg;

	char buf[BUFSIZE];
	int ret = -1;
	printf("handle thread :newfd = %d\n",newfd);

	while(1)
	{
		do
		{
			bzero(buf,BUFSIZE);
			ret = read(newfd,buf,BUFSIZE-1);
		}while(ret < 1);
		if(ret < 0)
		{
			exit(1);
		}
		if(!ret)
		{
			break;
		}
		printf("receive data:%s\n",buf);

		if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))
		{
			printf("Client is exiting!\n");
			break;
		}
	}

	close(newfd);
	return NULL;
}

每个客户端,都由一个独立的线程服务!

同时也把客户端代码优化一下,以前的客户端代码,IP地址和端口号是写死的,我们改成命令行传参

复制代码
int main(int argc, char **argv)
{
    port = atoi(argv[2]);
    sin.sin_addr.s_addr = inet_addr(argv[1]);
}

这样客户端更灵活,相连接不同的服务器,不用总是修改代码,想连谁在终端输入对应的IP地址和端口号就行

服务器端

复制代码
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include<stdlib.h>
#include <strings.h>
#include <arpa/inet.h>
#include<string.h>
#include <pthread.h>

#define QUIT_STR "QUIT"
#define BUFSIZE 1024
#define BACKLOG 5
#define SERV_IP 5001
#define SERV_IP_ADDR "192.168.88.129"

void* client_data_handle(void* arg);
int main()
{
	int fd = -1;

	struct sockaddr_in sin;
	//1.socket
	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd<0)
	{
		perror("socket");
		exit(1);
	}

	bzero(&sin,sizeof(sin));

	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_IP);
	//sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);  
	sin.sin_addr.s_addr = INADDR_ANY;
	/*if(inet_pion(AF_INET,SERV_IP_ADDR,(void *)sin.sin_addr.s_addr) != 1)
	  {
	  perror("inet_pton");
	  exit(1);
	  }
	  */
	//2.bind
	if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)) <0)
	{
		perror("bind");
		exit(0);
	}
	//3.listen
	if(listen(fd,BACKLOG) < 0)
	{
		perror("listen");
		exit(1);
	}

	//4.accept
	/*int newfd = -1;
	  newfd = accept(fd,NULL,NULL);
	  if(newfd < 0)
	  {
	  perror("accept");
	  exit(1);
	  }
	  */

	pthread_t tid;

	int newfd = -1;
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	while(1)
	{
		newfd = accept(fd,(struct sockaddr *)&cin,&addrlen);
		if(newfd < 0)
		{
			perror("accept");
			exit(1);
		}

		char ipv4_addr[16];
		if(!inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
		{
			perror("inet_ntop");
			exit(1);
		}
		printf("Client:(%s,%d) is connect\n",ipv4_addr,ntohs(cin.sin_port));

		pthread_create(&tid,NULL,client_data_handle,(void *)&newfd);
	}
	close(fd);

	return 0;
}

void* client_data_handle(void* arg)
{
	int newfd = *(int *)arg;

	char buf[BUFSIZE];
	int ret = -1;
	printf("handle thread :newfd = %d\n",newfd);

	while(1)
	{
		do
		{
			bzero(buf,BUFSIZE);
			ret = read(newfd,buf,BUFSIZE-1);
		}while(ret < 1);
		if(ret < 0)
		{
			exit(1);
		}
		if(!ret)
		{
			break;
		}
		printf("receive data:%s\n",buf);

		if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))
		{
			printf("Client is exiting!\n");
			break;
		}
	}

	close(newfd);
	return NULL;
}

客户端

复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
//  ./client 192.168.88.129   5001



#define SERV_PORT 5001
#define SERV_IP_ADDR "192.168.88.129"
#define BUFSIZE 1024
#define QUIT_STR "QUIT"

int main(int argc,char **argv)
{
	int fd = -1;
	if(argc != 3)
	{
		exit(1);
	}
	int port = -1;
	port = atoi(argv[2]);

	struct sockaddr_in sin;
	fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket");
		exit(1);
	}

	bzero(&sin,sizeof(sin));

	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = inet_addr(argv[1]);

	if(connect(fd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		perror("connect");
		exit(1);
	}

	char buf[BUFSIZE];
	while(1)
	{
		bzero(buf,BUFSIZE);

		if(fgets(buf,BUFSIZE-1,stdin) == NULL)
		{
			continue;
		}
		write(fd,buf,strlen(buf));

		if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))
		{
			break;
		}
	}

	return 0;
}

成功实现了

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux