0
点赞
收藏
分享

微信扫一扫

Linux下c语言TCP多线程聊天室


前言

开发环境:Linux(ubuntu 12.04),GCC

编译:

gcc server.c -lpthread -std=gnu99 -o s
gcc client.c -lpthread -std=gnu99 -o c

相关知识:TCP

附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制)。

效果图

运行服务端

Linux下c语言TCP多线程聊天室_C

运行2个客户端

Linux下c语言TCP多线程聊天室_C_02

其中一个客户端发送消息

Linux下c语言TCP多线程聊天室_Linux_03

互相发送

Linux下c语言TCP多线程聊天室_多线程_04

整体效果图

Linux下c语言TCP多线程聊天室_多线程_05

客户端发送"quit"断开连接。

代码下载

那么话不多说,放码过来:

码云:传送门,GitHub:传送门

代码

服务端:server.c

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

struct sockaddr_in addr = {};
int clifd_index = 0; // clifd的下标
char buf[1024] = {}; // 存储客户端发来的字符串
char str[1024] = {}; // 存储带clifd的回传信息
int clifd[30] = {}; // 存储clifd
int online_num = 0;	// 连接人数
int max_num = 10; // 最大人数

// 项目有bug,连接人数的限制控制不住,有待改进

void* start_read(void *arg) // 读取信息的子线程
{
//	printf("arg:%d\n",*(int*)arg);
	int clifd1 = *(int*)arg;
	printf("run_clifd:%d\n",clifd1);

	for(;;)
	{
//		printf("before read\n");

		int ret = read(clifd1,buf,sizeof(buf));
		printf("\nip:%s,port:%hu,size:%d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),ret); // 获取相关信息
		printf("say:%s\n",buf);
		
		char id[10] = {};
		sprintf(id,"%d说:",clifd1);

		if(strlen(buf) != 0)
		{
			strcpy(str,id);
			strcat(str,buf);
		} // 存入str中

		if(0 == strcmp("quit",buf)) // 如果收到quit
		{
			online_num--; // 在线人数-1
			for(int i=0; i<clifd_index; i++)
			{
				if(clifd1 == clifd[i])
				{
					int *die = &clifd1;
					clifd[i] = 0;
					pthread_exit(die); // 终止线程
					break;
				}
			}
		}
		//usleep(1000);
	}
}

void* start_write(void *arg) // 写回的子线程
{
//	printf("arg:%d\n",*(int*)arg);

//	usleep(500);

	int clifd1 = *(int*)arg;

	printf("run_clifd:%d\n",clifd1);

	for(;;)
	{
		int flag = 0;
		for(int i=0; i<clifd_index; i++) // 因为读到quit的原因,clifd被置0
		{
			if(clifd1 == clifd[i])
			{
				break;
			}
			if(i == clifd_index-1)
			{
				int *die = &clifd1;
				flag = 1;
				pthread_exit(die); // 终止此写回的子线程
			}
		}
		if(flag == 1)
		{
			break;
		}

		if(strlen(str) == 0) // 空消息不写入
			continue;
		printf("before write\n");
		printf("str:%s\n",str);
		write(clifd1,str,strlen(str)+1);
		usleep(50000); // 最快的子线程等待其他子线程
		memset(str,0,1024); // 清空str
	}
}

int main()
{
	printf("服务器创建socket...\n");
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(0 > sockfd)
	{
		perror("socket");
		return -1;
	}

	printf("准备地址...\n");
	
	addr.sin_family = AF_INET;
	addr.sin_port = htons(6008);//端口号
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");//你的ip地址(或服务器的私网ip)
	socklen_t len = sizeof(addr);

	printf("绑定socket与地址...\n");
	if(bind(sockfd,(struct sockaddr*)&addr,len))
	{
		perror("bind");
		return -1;
	}

	printf("设置监听...\n");
	if(listen(sockfd,2))
	{
		perror("listen");
		return -1;
	}


	printf("等待客户端连接...\n");
	for(;;)
	{
		if(online_num < max_num)
		{
			struct sockaddr_in addrcli = {};
			clifd[clifd_index] = accept(sockfd,(struct sockaddr*)&addrcli,&len);
		
			int flag = 0;
			for(int i=0; i<clifd_index; i++)
			{
				if(clifd[clifd_index] == clifd[i])
				{
					flag = 1;
					break;
				}
			}

			if(flag == 1)
			{
				clifd_index--;
				continue;
			}
			else
			{
				char link[50] = {};
				char link1[40] = "您已经成功连接";
				sprintf(link,"您的id是:%d,",clifd[clifd_index]);
				strcat(link,link1);
				write(clifd[clifd_index],link,strlen(link)+1);
				online_num++;
			}
		}
		else
		{
			continue;
		}


		if(0 > clifd[clifd_index])
		{
			perror("accept");
			continue;
		}

		printf("clifd:%d\n",clifd[clifd_index]);

		// 创建子线程
		pthread_t pid1,pid2;
		pthread_create(&pid1,NULL,start_read,&clifd[clifd_index]);
		pthread_create(&pid2,NULL,start_write,&clifd[clifd_index]);

		usleep(1000);

//		printf("clifd:%d\n",clifd[index]);

		clifd_index++; // 下标逐渐+1,这样写不是很合适

	}
	return 0;
}

客户端:client.c

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>

void* start_read(void* arg) // 读取信息
{
	int sockfd = *(int*)arg;
	char buf[1024] = {};
	for(;;)
	{
		read(sockfd,buf,sizeof(buf));
		if(strlen(buf) != 0)
		{
			printf("\n>%s\n",buf);
		}
	}
}

int main()
{
	printf("服务器创建socket...\n");
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(0 > sockfd)
	{
		perror("socket");
		return -1;
	}

	printf("准备地址...\n");
	struct sockaddr_in addr = {};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(6008);//设置的端口号
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");//你的ip地址(或服务器的公网ip)
	socklen_t len = sizeof(addr);

	printf("绑定连接服务器...\n");
	if(connect(sockfd,(struct sockaddr*)&addr,len))
	{
		perror("connect");
		return -1;
	}

	
	char link[50] = {};
	read(sockfd,link,sizeof(link));
//	printf("link:%s\n",link);
	if(strstr(link,"您已经成功连接")==NULL)
	{
		printf("连接人数已满,请稍后重试\n");
		return 0;
	}
	else
	{
		printf("link:%s\n",link);
	}

	// 创建读取子线程
	pthread_t pid;
	pthread_create(&pid,NULL,start_read,&sockfd);

	for(;;)
	{
		char buf[1024] = {};
		usleep(1000);
		//printf(">我说:");
		gets(buf);
		write(sockfd,buf,strlen(buf)+1);
		if(0 == strcmp("quit",buf))
		{
			printf("通信结束!\n");
			break;
		}
	}
	
	close(sockfd);
}

 

举报

相关推荐

0 条评论