MFC多客户端与一个服务器通信 跑通Windows Demo
1. 简介
本教程旨在指导您如何使用Microsoft Foundation Classes (MFC) 在Windows平台上创建一个多客户端与一个服务器通信的简单Demo,我们将使用TCP/IP协议来实现客户端和服务器之间的数据传输。
2. 环境准备
Visual Studio 2019 或更高版本
Windows 10 或更高版本
3. 创建项目
1、打开Visual Studio,选择“创建新项目”。
2、在“创建新项目”对话框中,选择“MFC AppWizard (Visual C++)”。
3、在“应用程序类型”中选择“Win32 Application”。
4、在“Win32应用程序类型”中选择“Single Document”。
5、点击“下一步”,在“应用程序设置”中输入项目名称,如“MultiClientServerDemo”。
6、点击“完成”创建项目。
4. 服务器端实现
4.1 添加必要的头文件
在服务器端的头文件中,添加以下头文件:
#include <winsock2.h> #include <ws2tcpip.h> #include <iostream> #include <vector> #include "CServerSocket.h"
4.2 服务器类定义
定义一个CServerSocket类,用于管理服务器端的套接字和客户端连接。
class CServerSocket : public CSocket { public: CServerSocket() {} ~CServerSocket() {} BOOL StartServer(int port); void AcceptClient(); void CloseClient(CSocket* pClientSocket); void SendMessageToClient(CSocket* pClientSocket, const char* message); void BroadcastMessage(const char* message); };
4.3 服务器类实现
实现CServerSocket类的方法,如下所示:
BOOL CServerSocket::StartServer(int port) { WSADATA wsaData; SOCKET listenSocket; sockaddr_in server; // 初始化Winsock WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSocket == INVALID_SOCKET) { std::cerr << "Failed to create socket: " << WSAGetLastError() << std::endl; return FALSE; } // 设置服务器地址结构 memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); // 绑定套接字 if (bind(listenSocket, (SOCKADDR*)&server, sizeof(server)) == SOCKET_ERROR) { std::cerr << "Failed to bind socket: " << WSAGetLastError() << std::endl; closesocket(listenSocket); WSACleanup(); return FALSE; } // 监听连接 listen(listenSocket, 5); return TRUE; } void CServerSocket::AcceptClient() { sockaddr_in client; int clientSize = sizeof(client); SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&client, &clientSize); if (clientSocket == INVALID_SOCKET) { std::cerr << "Failed to accept client: " << WSAGetLastError() << std::endl; return; } // 处理客户端连接 // ... } void CServerSocket::CloseClient(CSocket* pClientSocket) { closesocket(pClientSocket>GetSocket()); } void CServerSocket::SendMessageToClient(CSocket* pClientSocket, const char* message) { int sent = send(pClientSocket>GetSocket(), message, strlen(message), 0); if (sent == SOCKET_ERROR) { std::cerr << "Failed to send message: " << WSAGetLastError() << std::endl; } } void CServerSocket::BroadcastMessage(const char* message) { for (auto it = clients.begin(); it != clients.end(); ++it) { SendMessageToClient(it>second, message); } }
4.4 主函数
在主函数中,创建CServerSocket对象,并启动服务器:
int main() { CServerSocket server; if (server.StartServer(12345)) { // 启动服务器循环 // ... } WSACleanup(); return 0; }
5. 客户端实现
5.1 添加必要的头文件
在客户端的头文件中,添加以下头文件:
#include <winsock2.h> #include <ws2tcpip.h> #include <iostream> #include "CClientSocket.h"
5.2 客户端类定义
定义一个CClientSocket类,用于管理客户端的套接字。
class CClientSocket : public CSocket { public: CClientSocket() {} ~CClientSocket() {} BOOL ConnectToServer(const char* ip, int port); void SendMessageToServer(const char* message); void ReceiveMessageFromServer(); };
5.3 客户端类实现
实现CClientSocket类的方法,如下所示:
BOOL CClientSocket::ConnectToServer(const char* ip, int port) { WSADATA wsaData; SOCKET clientSocket; sockaddr_in server; // 初始化Winsock WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket == INVALID_SOCKET) { std::cerr << "Failed to create socket: " << WSAGetLastError() << std::endl; return FALSE; } // 设置服务器地址结构 memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(ip); server.sin_port = htons(port); // 连接到服务器 if (connect(clientSocket, (SOCKADDR*)&server, sizeof(server)) == SOCKET_ERROR) { std::cerr << "Failed to connect to server: " << WSAGetLastError() << std::endl; closesocket(clientSocket); WSACleanup(); return FALSE; } return TRUE; } void CClientSocket::SendMessageToServer(const char* message) { int sent = send(GetSocket(), message, strlen(message), 0); if (sent == SOCKET_ERROR) { std::cerr << "Failed to send message: " << WSAGetLastError() << std::endl; } } void CClientSocket::ReceiveMessageFromServer() { char buffer[1024]; int received = recv(GetSocket(), buffer, sizeof(buffer), 0); if (received > 0) { buffer[received] = ''; std::cout << "Received message: " << buffer << std::endl; } else if (received == 0) { std::cerr << "Server closed the connection" << std::endl; } else { std::cerr << "Failed to receive message: " << WSAGetLastError() << std::endl; } }
5.4 主函数
在主函数中,创建CClientSocket对象,并连接到服务器:
int main() { CClientSocket client; if (client.ConnectToServer("127.0.0.1", 12345)) { // 发送消息 client.SendMessageToServer("Hello, Server!"); // 接收消息 client.ReceiveMessageFromServer(); // 关闭连接 closesocket(client.GetSocket()); } WSACleanup(); return 0; }
6. 运行Demo
1、打开两个命令行窗口。
2、在第一个窗口中,编译并运行服务器端程序。
3、在第二个窗口中,编译并运行客户端程序。
客户端应该能够连接到服务器,并能够发送和接收消息。
7. 总结
本教程向您展示了如何使用MFC在Windows平台上创建一个多客户端与一个服务器通信的简单Demo,您可以根据需要扩展此Demo,添加更多的功能,例如广播消息、多线程处理等。