C++ select模型简单聊天室

1,127 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

C++ select模型简单聊天室

TIPS:以下使用CMake项目进行开发。关于何为CMake,链接:blog.csdn.net/qq135595696…

简单聊天室效果展示

简单聊天室服务端源码(使用select模型)

// Server0327.cpp: 定义应用程序的入口点。
//

#include "Server0327.h"
#include <WinSock2.h>
#include <vector>

#pragma comment(lib,"ws2_32.lib")

using namespace std;
class TcpServer
{
public:
	bool Listen(const char* ip, int port)
	{
		//创建socket
		_serverSock = socket(AF_INET, SOCK_STREAM, 0);
		if (INVALID_SOCKET == _serverSock)
			goto Exit;
		//绑定IP和端口号
		SOCKADDR_IN addr;
		addr.sin_addr.s_addr = inet_addr(ip);
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		if (INVALID_SOCKET == bind(_serverSock, (sockaddr*)&addr, sizeof(SOCKADDR_IN)))
			goto Exit;

		//监听端口
		if (INVALID_SOCKET == listen(_serverSock, 255))
			goto Exit;

		return true;
	Exit:
		closesocket(_serverSock);
		_serverSock = INVALID_SOCKET;
		return false;
	}


	void Update()
	{
		FD_SET reads;
		FD_ZERO(&reads);
		FD_SET(_serverSock, &reads);

		for (auto&& clientSock : _clientSocks)
			FD_SET(clientSock, &reads);

		int nRet = select(0, &reads, nullptr, nullptr, nullptr);
		if (nRet > 0)
		{
			if (FD_ISSET(_serverSock, &reads))
				Accept();
			else
			{
				for (int i = 0; i < _clientSocks.size(); i++)
				{
					if (FD_ISSET(_clientSocks[i], &reads))
					{
						char buf[1024]{ 0 };
						int nRecv = recv(_clientSocks[i], buf, 1024, 0);
						if (nRecv > 0)
							OnNetMsg(_clientSocks[i], buf, sizeof(buf));
						if (nRecv <= 0)
						{
							closesocket(_clientSocks[i]);
							OnDisConnect(_clientSocks[i]);
							_clientSocks.erase(_clientSocks.begin() + i);
							continue;
						}
					}
				}
			}
		}
	}

	void Accept()
	{
		SOCKADDR_IN clientAddr;
		int clientAddrLen = sizeof(clientAddr);
		SOCKET clientSock = accept(_serverSock, (sockaddr*)&clientAddr, &clientAddrLen);
		if (INVALID_SOCKET != clientSock)
		{
			_clientSocks.push_back(clientSock);
			OnConnect(clientSock);
		}

	}

	void OnConnect(SOCKET clientSock)
	{
		printf("%d 客户端连接\n", clientSock);
	}

	int OnNetMsg(SOCKET clientSock, const char* buff, int len)
	{
		printf("%d == %s\n", clientSock, buff);
		for (auto&& clientSock : _clientSocks)
			send(clientSock, buff, len, 0);
		return len;
	}


	void OnDisConnect(SOCKET sock)
	{
		printf("%d==客户端断开连接\n", sock);
	}



private:
	SOCKET _serverSock;
	vector<SOCKET> _clientSocks;
};



int main()
{
	WSADATA wsa;
	WSAStartup(MAKEWORD(2, 2), &wsa);

	TcpServer server;
	server.Listen("0.0.0.0", 7890);
	while (true)
		server.Update();

	WSACleanup();
	return 0;
}

简单聊天室客户端源码(使用多线程)

// CMakeClient0331.cpp: 定义应用程序的入口点。
//

#include "CMakeClient0331.h"
#include<iostream>
#include<WinSock2.h>
#include<thread>

#pragma comment(lib,"ws2_32.lib")


int main()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET clientSock = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == clientSock)
	{
		closesocket(clientSock);
		WSACleanup();
		return 0;
	}

	SOCKADDR_IN serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serverAddr.sin_port = htons(7890);
	if (INVALID_SOCKET == connect(clientSock, (sockaddr*)&serverAddr, sizeof(SOCKADDR_IN)))
	{
		closesocket(clientSock);
		WSACleanup();
		return 0;
	}
	std::cout << "已连接服务端" << std::endl;

	std::thread t([&clientSock] {
		while (true)
		{
			char buf[1024]{ 0 };
			int nRecvLen = recv(clientSock, buf, 1024, 0);
			if (nRecvLen <= 0)
				break;
			std::cout << "接收数据长度:" << nRecvLen << " 接受数据:" << buf << std::endl;
		}
		});
	t.detach();



	while (true)
	{
		char buf[1024]{ 0 };
		std::cin >> buf;
		if (buf[0] == 'q')break;
		int nSendLen = send(clientSock, buf, sizeof(buf), 0);
	}

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

版本声明:本文为CSDN博主[ufgnix0802]的原创文章。
原文链接:(blog.csdn.net/qq135595696…)