C-S结构的多clients聊天室

服务器

  • 流程
  1. 初始化WinSock

  2. 创建套接字serverSocket

  3. 设置服务器地址及端口信息

  4. 绑定地址到serverSocket

  5. 监听并设置客户端连接个数

  6. while true
    接收连接并返回一个套接字clients[i]

    注意:clients是一个SOCKET数组,对应请求连接的客户端

    创建线程,返回一个句柄,将线程函数名作起始地址传递,并将i作下标传递
    关闭句柄
    
  7. WSACleanup以及套接字关闭处理

  8. 线程函数:接收clients[i]传递的消息并转发给已连接的客户实现聊天室功能

  • 代码
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

#define IP_ADDRESS "127.0.0.1"	//本地地址
#define PORT 5555

const int LEN = 10;			//最大连接客户数
SOCKET clientScoket[LEN];	//客户i对应的SOCKET
int curMax = 0;				//已经连接的客户个数,不超过LEN

const int BufSize = 2000;
//创建线程
DWORD WINAPI ClientThread(LPVOID ipParameter)
{
	int ind=(int)ipParameter;
	int RET = 0;
	char RecvBuffer[BufSize];
	while (true) {
		//Init RecvBuffer 
		memset(RecvBuffer, 0, sizeof(RecvBuffer));
		RET = recv(clientScoket[ind], RecvBuffer, BufSize, 0);
		if (RET == 0 || RET == SOCKET_ERROR){
			cout << "-----------------------------------------------------------------------\n";
			cout << ind << "号离开 \n";
			cout << "-----------------------------------------------------------------------\n";
			break;
		}
		cout << ind << ":" << RecvBuffer << endl;

		// transmit
		char SendBuffer[BufSize];
		SendBuffer[0] = ind + '0';
		SendBuffer[1] = ':';
		int i = 0;
		for (; i < strlen(RecvBuffer); ++i) SendBuffer[i + 2] = RecvBuffer[i];
		SendBuffer[i + 2] = '\0';

		for (i = 0; i < curMax; ++i) {
			if (i != ind) {
				int ret = send(clientScoket[i], SendBuffer, (int)strlen(SendBuffer), 0);
				if (ret == SOCKET_ERROR) {
					cout << "send to error" << endl;
					break;	//maybe break can't solve this problem.
				}
			}
		}
	}
	return 0;
}


int main()
{
	WSADATA wsa;
	SOCKET severSocket;
	struct sockaddr_in localAddr, clientAddr;
	HANDLE h = NULL;
	int RET;
	//Init WinSock
	if ( WSAStartup(MAKEWORD(2, 2), &wsa) != 0){
		cout << "WSAStartup's init failed! \n";
		return -1;
	}

	//Create SOCKET:TCP(AF_INET	SOCK_STREAM)
	severSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (severSocket == INVALID_SOCKET) {
		cout << "socket failed" << GetLastError() << endl;
		return -1;
	}

	//Set server's address
	memset(&localAddr, 0, sizeof(localAddr));
	localAddr.sin_family = AF_INET;
	localAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
	localAddr.sin_port = htons(PORT);

	//bind socket
	RET = bind(severSocket, (struct sockaddr*)&localAddr, sizeof(localAddr));
	if (RET != 0){
		cout << "bind failed \n";
		return -1;
	}

	//listen LEN
	RET = listen(severSocket, LEN);
	if (RET != 0){
		cout << "listen failed \n";
		return -1;
	}

	cout << "---------------------------- Server starts ----------------------------\n";
	int index=0;//index th client
	while (true){
		// accept
		int addrLen = sizeof(clientAddr);
		clientScoket[index] = accept(severSocket, (struct sockaddr*)&clientAddr, &addrLen);
		if (clientScoket[index] == INVALID_SOCKET){
			cout << "accept failed \n";
			break;
		}

		// client information
		cout << "-----------------------------------------------------------------------\n";
		cout << "Client:" << index << " connect \n"
			<< "Address:" << inet_ntoa(clientAddr.sin_addr) << " & Port:" << clientAddr.sin_port << endl;
		cout << "-----------------------------------------------------------------------\n";
		
		// assgin the task to Thread with SOCKET clientSocket[index]
		h = CreateThread(NULL, 0, ClientThread, (LPVOID)index, 0, NULL);
		++index;
		++curMax;
		if (h == NULL) {
			cout << "Create thread failed \n";
			break;
		}
		CloseHandle(h);
	}

	closesocket(severSocket);
	for (int i(0); i < index;++i)
		closesocket(clientScoket[i]);
	WSACleanup();
	return 0;
}

客户端

  • 流程
  1. 初始化WinSock
  2. 创建套接字clientSocket
  3. 设置服务器地址及端口信息
  4. 连接
  5. 创建线程函数接收消息
  6. while true
    发送当前用户输入的消息
  7. WSACleanup以及套接字关闭处理
  8. 线程函数:接收服务器转发的消息
  • 代码
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;

#define PORT 5555
#define IP_ADDRESS "127.0.0.1"

const int BufSize = 2000;


DWORD WINAPI ServerThread(LPVOID ipParameter)
{
	SOCKET clientSocket = (SOCKET)ipParameter;
	int RET = 0;
	char RecvBuffer[BufSize];
	//初始化 recvBuffer 
	while (true) {
		memset(RecvBuffer, 0, sizeof(RecvBuffer));
		RET = recv(clientSocket, RecvBuffer, BufSize, 0);
		if (RET == 0 || RET == SOCKET_ERROR){
			cout << "error" << endl;
			break;
		}
		cout << RecvBuffer << endl;
	}
	return 0;
}

int main()
{
	WSADATA wsa;
	SOCKET clientScoket;
	struct sockaddr_in  serveAddr;
	HANDLE h = NULL;
	int RET = 0;
	char SendBuffer[BufSize];
	
	// Init WinSock
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0){
		cout << "Init WinSock failed" << endl;
		return -1;
	}

	// creat socket
	clientScoket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientScoket == INVALID_SOCKET){
		cout << "socket failed" << GetLastError() << endl;
		return -1;
	}

	// set server's address
	memset(&serveAddr, 0, sizeof(serveAddr));
	serveAddr.sin_family = AF_INET;
	serveAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
	serveAddr.sin_port = htons(PORT);
	

	RET = connect(clientScoket, (struct sockaddr*)&serveAddr, sizeof(serveAddr));
	if (RET != 0){
		cout << "connect failed \n";
		return -1;
	}
	else cout << "------------------------- Connect successfully -------------------------\n";

	//等待消息
	h = CreateThread(NULL, 0, ServerThread, (LPVOID)clientScoket, 0, NULL);

	while (true){
		cin.getline(SendBuffer, sizeof(SendBuffer));
		RET = send(clientScoket, SendBuffer, (int)strlen(SendBuffer), 0);
		if (RET == SOCKET_ERROR){
			cout << "send to error" << endl;
			break;
		}
	}
	closesocket(clientScoket);
	CloseHandle(h);
	WSACleanup();
	return 0;
}

#效果显示截图
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值