C语言多人聊天室,Socket网络编程

多人聊天室,Windows黑窗口
两个程序:service和client
需要先启动service,再启动client输入IP。

实现步骤
service:

  1. 先创建一个listen
  2. 循环去监听连接请求
  3. 收到一个请求时,先将该连接实例存储在全局的hash_map中
  4. 再创建一个线程去监听该连接发送的消息
  5. 子线程收到消息就向hash_map中所有连接群发消息
  6. 客户端连接到服务器后,创建一个子线程去接收服务器的消息,主线程

client:

  1. 连接服务器
  2. 创建子线程监听服务器的消息
  3. 主线程循环等待用户发送数据

service代码:

#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "pthreadVC2.lib")
#define max_conn_number 20
using namespace std;

typedef struct client {
	int id;
	char *name;
	SOCKET socket;
}Client;
pair<int, Client> Pair;
hash_map<int,Client> clients;
const char *fenge = ":";
const char *wellcome_str = "welcome to connect us,your first input is your name:\0";
int wellcome_length = strlen(wellcome_str);
int conn_number=0;

void *client_run(void *args)
{
	Client *client = (Client *)args;
	if (client->socket == INVALID_SOCKET)
	{
		printf("accept error !");
		closesocket(client->socket);
	}
	send(client->socket, wellcome_str, wellcome_length, 0);
	printf("新线程处理连接\n");
	//将接收第一条数据作为名字
	char name[1024];
	int ret = recv(client->socket, name, 1023, 0);
	if (ret > 0)
	{
		client->name = name;
		name[ret] = 0x00;//添加结束符
	}
	char recvData[1024];
	char *sendData = (char *)malloc(1024 * sizeof(char));
	while (1)
	{
		int ret = recv(client->socket, recvData, 1023, 0);//监听消息
		if (ret < 0)break;//断开连接
		memset(sendData, 0, 1024);
		recvData[ret] = 0x00;//添加结束符
		sprintf(sendData, "%s%s", client->name, fenge);//拼接字符串
		sprintf(sendData, "%s%s", sendData, recvData);//拼接字符串
		for (auto iter = clients.begin(); iter != clients.end(); ++iter) {//群发
			if (iter->first == client->id)continue;
			send(iter->second.socket, sendData, strlen(sendData), 0);
		}
	}
	clients.erase(client->id);
	conn_number--;
	closesocket(client->socket);
	printf("一个连接断开线程执行完毕\n");
	return NULL;
}

void findIP(char *ip, int size)
{
	WORD v = MAKEWORD(1, 1);
	WSADATA wsaData;
	WSAStartup(v, &wsaData); // 加载套接字库

	struct hostent *phostinfo = gethostbyname("");
	char *p = inet_ntoa(*((struct in_addr *)(*phostinfo->h_addr_list)));
	strncpy(ip, p, size - 1);
	ip[size - 1] = '\0';
	WSACleanup();
}


int main(int argc, char* argv[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)return -1;

	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//通信协议类型,数据类型,访问方式
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		WSACleanup();
		return -2;
	}

	printf("创建套接字成功!\n");
	char ip[20] = { 0 };
	findIP(ip, sizeof(ip));
	//绑定IP和端口
	sockaddr_in addr;
	addr.sin_family = AF_INET;//协议版本
	addr.sin_port = htons(8888);//
	addr.sin_addr.S_un.S_addr = inet_addr(ip);
	int r = bind(slisten, (LPSOCKADDR)&addr, sizeof(addr));
	if (r == SOCKET_ERROR)
	{
		printf("bind error !");
		closesocket(slisten);
		return -3;
	}

	printf("绑定套接字成功!IP是:%s。\n",ip);
	if (listen(slisten, 10) == SOCKET_ERROR)
	{
		printf("listen error !");
		return -4;
	}
	//循环接收连接

	int i = 0;//socket数组下标,自增ID
	Client *client;
	pthread_t *thread;
	SOCKADDR remote_addr;
	int remote_addr_rlen=sizeof(remote_addr);
	while (conn_number<=max_conn_number)
	{
		client = (Client *)malloc(sizeof(Client));
		thread= (pthread_t *)malloc(sizeof(pthread_t));
		printf("等待连接...\n");
		client->socket = accept(slisten, &remote_addr, &remote_addr_rlen);//接收连接
		if (client->socket < 0)
		{
			free(client);
			printf("接收失败\n");
			continue;
		}
		client->id = i;
		clients[i] = *client;//把连接存储在hash_map
		printf("接收到一个连接,开启新线程处理\n");
		conn_number++;
		pthread_create(thread, NULL, client_run, &clients[i]);
		i++;
	}

	closesocket(slisten);
	WSACleanup();
	return 0;
}

client代码:

#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include 
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "pthreadVC2.lib")
void *receive_message(void *args)
{
	SOCKET *sClient = (SOCKET *)args;
	char *recvData = (char *)malloc(1024 * sizeof(char));
	recvData[1023]='\0';
	int ret;
	while(1)
	{
		ret = recv(*sClient, recvData, 1023, 0);
		if (ret < 0)break;
		recvData[ret] = 0x00;//添加结束符
		printf("%s\n", recvData);
	}
	free(recvData);
	closesocket(*sClient);
	return NULL;
}

int main(int argc, char* argv[])
{
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)return -1;
	printf("初始化WSA成功!\n");

	SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//通信协议类型,数据类型,访问方式
	if (sClient == INVALID_SOCKET)
	{
		printf("socket error !");
		WSACleanup();
		return -2;
	}

	char server_ip[20] = { 0 };
	printf("创建套接字成功!请输入服务器IP:\n");
	scanf("%s", &server_ip);
	//获取服务器协议族
	sockaddr_in addr;
	addr.sin_family = AF_INET;//协议版本
	addr.sin_port = htons(8888);//
	addr.sin_addr.S_un.S_addr = inet_addr(server_ip);
	if (connect(sClient, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
	{
		printf("connect error !");
		closesocket(sClient);
		return -3;
	}

	printf("连接服务器(%s)成功!\n",server_ip);
	pthread_t thread;
	pthread_create(&thread, NULL, receive_message, (void *)&sClient);//开启新线程,接收服务器发送的消息

	char *sendData = (char *)malloc(1024 * sizeof(char));;
	sendData[1023] = '\0';
	while (true)
	{
		memset(sendData, 0, 1024);
		scanf("%s", sendData);
		if (sendData == "quit\0")break;
		send(sClient, sendData, strlen(sendData), NULL);
	}
	free(sendData);
	closesocket(sClient);
	WSACleanup();
	return 0;
}

你可能感兴趣的:(socket,多线程,c++,网络,socket,多线程,c++)