Linux局域网中 TCP 多线程 Server + Client 聊天室程序源码

这是一个Linux局域网TCP多线程Server + Client聊天室程序的源码实现,包括TCP服务器初始化、接收连接、发送消息到所有客户端等功能。使用信号处理函数处理关闭请求,通过线程处理每个客户端的通信。
摘要由CSDN通过智能技术生成
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define TYPE_VER 8001

typedef struct tag_tk {
	int g_connfd;
	char name[100];
}	TK;

TK tk[100] = {};

void sigint (int signum) {
	printf ("聊天服务器即将关闭...\n");
	int i = 0;
	for (i = 0; i < 100; i++) {
		close (tk[i].g_connfd);
	}
	exit (0);
}

// TCP服务器向所有客户端发送接收到的内容
void sendall (int num, char buf[], int size) {
	int i = 0;
	for (i = 0; i < 100; i++) {
		if (tk[i].g_connfd == 0 || num == i) {
			continue;
		}
		if (send (tk[i].g_connfd, buf, size, 0) == -1) {
			perror ("Error->send:");
			//break;
		}
//		printf ("发送了一次 i:%d\n", i);
	}
}

// TCP服务器初始化  传入指定端口 准备通信之前的各自数据,绑定并监听,返回监听的套接字描述符
int init (unsigned short type) {
	int sockfd = socket (AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		perror ("Error->socket");
		return -1;
	}
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons (type);
	addr.sin_addr.s_addr = INADDR_ANY;
	if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1) {
		perror ("Error->bind");
		return -1;
	}
	if (listen (sockfd, 1024) == -1) {
		perror ("Error->listen");
		return -1;
	}
	return sockfd;
}
void* thread_proc (void* arg) {
	pthread_detach (pthread_self ());
	char req[1024];
	int i = (int)arg;
	for (;;) {
		while (! strlen (tk[i].name)) {
			ssize_t rb = recv (tk[i].g_connfd, tk[i].name, sizeof (tk[i].name), 0);
			if (rb == -1) {
				perror ("Error-<recv");
				continue;
			}
			printf ("%s :加入会话!  i:%d\n", tk[i].name, i);
		}
		ssize_t rb = recv (tk[i].g_connfd, req, sizeof (req), 0);
		if (rb == -1) {
			perror ("Error-<recv");
			continue;
		}
		if (rb == 0) {
			printf ("%s : 退出会话!\n", tk[i].name);
			break;
		}
//		printf ("%s>:%s\n", tk[i].name, req);
		sendall (i, req, rb);
		/*
		if (send (tk[i].g_connfd, req, sizeof (rb), 0) == -1) {
			perror ("Error->send");
			break;
		}
		*/
		//  服务器接收到客户端的消息,再次转发给所有的在线客户端
	}
	close (tk[i].g_connfd);
	tk[i].g_connfd = 0;
	return NULL;
}





// TCP服务器接收聊天内容
int rcvreq (int sockfd) {
	int i = 0;
	for (;;) {
		for (i = 0; i < 100; i++) {
			if (tk[i].g_connfd == 0) {
				break;
			}
		}
		struct sockaddr_in addrcli = {};
		socklen_t addrlen = sizeof (addrcli);
		if ((tk[i].g_connfd = accept (sockfd, (struct sockaddr*)&addrcli, &addrlen)) == -1) {
			perror ("Error->accept");
			printf ("sockfd:%d\n", sockfd);
		}
		pthread_t tid;
		printf ("客户端:%s 请求加入会话!  i:%d\n", inet_ntoa (addrcli.sin_addr), i);
		pthread_create (&tid, NULL, thread_proc, (void*)i);
	}
	return 0;

}

int main (void) {
	if (signal (SIGINT, sigint) == SIG_ERR) {
		perror ("Error->sigint");
		return -1;
	}
	int g_sockfd = -1;
	if ((g_sockfd = init (TYPE_VER)) == -1) {
		return -1;
	}
	printf ("聊天室服务器准备就绪...\n");
	rcvreq (g_sockfd);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值