(转)聊天室的初步构建

本文档详细介绍了如何使用C语言在VS2019环境下实现一个单线程和多线程的TCP聊天室。主要内容包括:利用套接字编程,通过TCP协议进行通信,设置服务器地址,绑定套接字,监听连接,接收和发送数据。多线程部分则展示了如何通过CreateThread创建线程来处理多个客户端连接。此外,还涉及了inet_pton和inet_ntop函数的使用。
摘要由CSDN通过智能技术生成

多线程聊天室

  1. 工作环境: vs2019;
  2. 原理:利用套接字编程,通过c代码实现;采用TCP协议。
  3. 目的:客户机可以向服务器发送信息(服务器向客户机发送信息本程序暂未实现),可以多客户机向服务器发信息。

单线程服务器模块

1.SOCKET建立套接字
确定版本信息

WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2) {
		printf("确定版本失败:%d\n", GetLastError());
		return -1;
	}
	printf("确定版本成功\n");

建立流套接字

SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serverSocket == SOCKET_ERROR) {
		printf("创建socket失败:%d\n", GetLastError());
		WSACleanup();
		return -1;
	}
	printf("确定socket成功\n");

头文件(所有)

#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

#include<windows.h>
#include<WS2tcpip.h>

2.设置服务器地址族

SOCKADDR_IN addr = { 0 };
	addr.sin_family = AF_INET;//必须与服务器的Socket中地址族相同
	inet_pton(AF_INET, "192.168.1.29", (void*)&addr.sin_addr.S_un.S_addr);
	//addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.29");//IP地址,把字符串变为整形,即点分十进制的IP变为网络字节顺序的IP地址
	addr.sin_port = htons(9527);//端口号

使用inet_addr(),vs会报错。由于在vs2013以后的版本中,增加了inet_pton()、InetPton()之类的新函数,用于IP地址在点分十进制和二进制整数之间转换,并且可以处理IPV4和IPV6,而inet_addr()是老函数,高版本vs在编译时默认使用了新函数,所以会报错。(转)
若使用inet_pton(),增加头文件,#include<WS2tcpip.h>。
否则,修改VS配置,告诉它我要旧函数:项目->c/c+±>常规->SDL检查,将‘是’改成‘否’。(转)

IP地址,为本主机连网时的IP地址,可以cmd(打开命令提示符)->ipconfig,即可查询。
在这里插入图片描述
3.绑定套接字和本地地址

int r = bind(serverSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR));
	if (r == -1) {
		printf("绑定失败:%d\n", GetLastError());
		closesocket(serverSocket);//断开连接
		WSACleanup();//清除版本信息
		return -1;
	}
	printf("绑定成功\n");

4.监听

r = listen(serverSocket, 10);
	if (r == -1) {
		printf("监听失败:%d\n", GetLastError());
		closesocket(serverSocket);//断开连接
		WSACleanup();//清除版本信息
		return -1;
	}
	printf("监听成功\n");

5.接受连接

SOCKADDR_IN addr_1 = { 0 };
	int len = sizeof(addr_1);
	SOCKET clientSocket= accept(serverSocket, (SOCKADDR*)&addr_1, &len);
	if (clientSocket == SOCKET_ERROR) {
		printf("服务器崩溃:%d\n", GetLastError());
		closesocket(serverSocket);//断开连接
		WSACleanup();//清除版本信息
		return -1;
	}
	//printf("客户端连接服务器成功:%s\n",inet_ntoa(addr_1.sin_addr));
	char buf[20] = { "0" };
	printf("客户端连接服务器成功:%s\n", inet_ntop(AF_INET,(void*)&addr_1.sin_addr,buf,16));

6.接收数据

char buffer[1024];
	while (1) {
		r = recv(clientSocket, buffer, 1023, NULL);
		if (r > 0) {
			buffer[r]=0;//添加结束符,否则出现乱码
			printf("来自客户端信息:%s\n", buffer);
		}
	}

7.结果:
在文件里的debug中,运行单线程服务器.exe,如图:
在这里插入图片描述
运行客户机之后,输入发送的数据,结果如图(服务器-客户机):
在这里插入图片描述
在这里插入图片描述

客户机模块

建立套接字、connect()连接、发送数据。

char buffer[1024];
	while (1) {
		//编译器提示scanf不安全,提倡使用scanf_s
		printf("请输入: ");
		scanf_s("%s", buffer,1023);
		send(clientSocket, buffer, strlen(buffer),NULL);
	}

其他与服务器类似

多线程服务器模块

利用线程实现,CreateThread();
设置客户机数组,在利用for循环接收数据。

//6.接收连接
	SOCKADDR_IN addr_1 = { 0 };
	int len = sizeof(addr_1);
	for (int i = 0; i < CLIENT_NUM; i++) {
		clientSocket[i] = accept(serverSocket, (SOCKADDR*)&addr_1, &len);
		if (clientSocket[i] == SOCKET_ERROR) {
			printf("服务器崩溃:%d\n", GetLastError());
			closesocket(serverSocket);//断开连接
			WSACleanup();//清除版本信息
			return -1;
		}
		//printf("客户端连接服务器成功:%s\n",inet_ntoa(addr_1.sin_addr));
		char buf[20] = { "0" };
		printf("客户端%d连接服务器成功:%s\n",i+1, inet_ntop(AF_INET, (void*)&addr_1.sin_addr, buf, 16));

		CreateThread(NULL,NULL,LPTHREAD_START_ROUTINE(func),(void *)i,NULL,NULL);//LPVOID即 void *

	}

截图:
在这里插入图片描述

小结

inet_pton,inet_ntop()参考了其他人的建议,代码是通过b站学习的。
希望对大家有帮助!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值