TCP通信 —— 实现线程池与多个客户端进行通信

34 篇文章 0 订阅
15 篇文章 0 订阅

直接上代码,简单粗暴:

 

服务器端:

int clifd[10];   /* 存放客户端套接字的数组 */
sem_t sem;   /* 信号量 */
pthread_mutex_t mutex;   /* 互斥锁 */

void initCli()   /* 初始化 */
{
	int i = 0;
	for(; i < 10; ++i)
	{
		clifd[i] = -1;
	}
}

int getCli()
{
	pthread_mutex_lock(&mutex);   /* 保证线程安全 */
	int c = clifd[0];   /* 获取先到客户端的套接字,先来先服务 */
	int i = 0;
	for(; (i < 9 && clifd[i] != -1); ++i)
	{
		clifd[i] = clifd[i+1];   /* 整理数组 */
	}
	clifd[i] = -1;

	pthread_mutex_unlock(&mutex);

	return c;
}

int insertCli(int c)   /* 插入接受到的客户端套接字 */
{
	int i = 0;
	for(; i < 10; ++i)
	{
		if(-1 == clifd[i])
		{
			clifd[i] = c;
			return 1;
		}
	}

	return -1;
}

void *pthread_fun(void *arg)   /* 函数线程, 即处理单元 */
{
	while(1)
	{
		sem_wait(&sem);   /* 对信号量进行P操作,如果目前没有可处理客户端连接则阻塞 */

		int c = getCli();   /* 获取客户端套接字 */
		while(1)
		{
			char buff[128] = {0};
			if(0 >= recv(c, buff, 127, 0))
			{
				printf("one client has exit!\n");
				break;   /* 切换到其他等待的客户端 */
			}
			printf("%d %s\n",c,buff);

			send(c, "ok", 2, 0);
		}
	}
}

int main()
{
	int s = sem_init(&sem, 0, 0);   /* 初始化信号量 */
	assert(s == 0);
	initCli();

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	assert(sockfd != -1);
	
	struct sockaddr_in ser,cli;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(6000);   /* 使用6000端口 */
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");   /* 回环地址 */

	int res = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));   /* 命名套接字 */
	assert(res != -1);

	res = listen(sockfd, 10);   /* 监听套接字 */
	assert(res != -1);

	int i = 0;
	for(; i < 3; ++i)    /* 预先创建好的线程池 */
	{
		pthread_t id;
		res = pthread_create(&id, NULL, pthread_fun, NULL);
	}

	while(1)
	{
		int len = sizeof(cli);
		int c = accept(sockfd, (struct sockaddr *)&cli, &len);   /* 获取客户端套接字 */

		if(-1 == insertCli(c))
		{
			close(c);   /* 插入失败说明超过可处理客户端数量,直接退出 */
			continue;
		}

		sem_post(&sem);   /* 获取客户端套接字后就对信号箱V操作以使函数线程开始工作 */
	}

}

 

客户端:

int main()
{
	int sockfd = socket(PF_INET, SOCK_STREAM, 0);
	assert(sockfd != -1);

	struct sockaddr_in ser,cli;
	memset(&ser, 0, sizeof(ser));

	ser.sin_family = PF_INET;
	ser.sin_port = htons(6000); //主机的地址格式转化到网络的地址格式(大小锻)
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");

	int c = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser));
	assert(c != -1);

	while(1)
	{
		char buff[128] = {0};
		fgets(buff,128,stdin);
		buff[strlen(buff) - 1] = 0;

		send(sockfd, buff, strlen(buff), 0);

		char recvbuf[128] = {0};
		recv(sockfd, recvbuf, 127, 0);
		printf("%s\n",recvbuf);

		if(strcmp(buff, "end") == 0)
			break;
	}
	close(c);

	exit(0);
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值