Windows下用CC++实现TCP, 服务器/客户端 "多人聊天室",客户端用户需要先注册再登陆,用户的注册信息保存在txt文件中,由服务器读取txt文件并接受用户客户端的连接,不能使用unistd.h库中的内容
时间: 2023-06-18 16:05:51 浏览: 49
实现TCP协议需要用到Winsock库,以下是一个简单的多人聊天室的服务器/客户端实现,仅供参考。
服务器端:
```c++
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
// 客户端信息结构体
struct ClientInfo
{
int id; // 客户端id
SOCKET socket; // 客户端socket
sockaddr_in addr; // 客户端地址信息
};
int main()
{
// 初始化Winsock库
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR)
{
std::cerr << "Error: Failed to initialize Winsock library!" << std::endl;
return 1;
}
// 创建服务器socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cerr << "Error: Failed to create server socket!" << std::endl;
WSACleanup();
return 1;
}
// 绑定服务器socket到端口
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(8888);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
std::cerr << "Error: Failed to bind server socket!" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 监听端口
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR)
{
std::cerr << "Error: Failed to listen on server socket!" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 创建客户端信息数组
const int MAX_CLIENTS = 10; // 最大客户端数量
ClientInfo clients[MAX_CLIENTS]; // 客户端数组
int numClients = 0; // 当前客户端数量
// 读取客户端注册信息
const char* REG_FILE = "users.txt"; // 注册信息保存的文件
FILE* fp = fopen(REG_FILE, "r");
if (fp == NULL)
{
std::cerr << "Error: Failed to open user registration file!" << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 读取每个客户端的注册信息
while (numClients < MAX_CLIENTS && !feof(fp))
{
char username[256], password[256];
if (fscanf(fp, "%s %s\n", username, password) != 2)
continue; // 读取失败,继续下一行
// 将注册信息保存到客户端数组中
clients[numClients].id = numClients + 1;
clients[numClients].socket = INVALID_SOCKET;
clients[numClients].addr.sin_family = AF_INET;
clients[numClients].addr.sin_addr.s_addr = htonl(INADDR_ANY);
clients[numClients].addr.sin_port = htons(0);
numClients++;
}
fclose(fp);
// 开始接受客户端连接
std::cout << "Server started, waiting for clients..." << std::endl;
while (true)
{
// 等待客户端连接
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &addrLen);
if (clientSocket == INVALID_SOCKET)
{
std::cerr << "Error: Failed to accept client connection!" << std::endl;
continue;
}
// 检查客户端是否已经注册
bool validClient = false;
int clientId = 0;
for (int i = 0; i < numClients; i++)
{
if (clients[i].socket == INVALID_SOCKET && strcmp(inet_ntoa(clientAddr.sin_addr), "127.0.0.1") != 0) // 检查客户端是否已经连接
{
clientId = clients[i].id;
clients[i].socket = clientSocket;
clients[i].addr = clientAddr;
validClient = true;
break;
}
}
if (validClient)
{
std::cout << "Client " << clientId << " connected from " << inet_ntoa(clientAddr.sin_addr) << std::endl;
}
else
{
std::cerr << "Error: Client " << inet_ntoa(clientAddr.sin_addr) << " rejected, maximum number of clients reached!" << std::endl;
closesocket(clientSocket);
continue;
}
// 开始处理客户端消息
char buf[1024];
int bytesRecv;
while ((bytesRecv = recv(clientSocket, buf, sizeof(buf), 0)) > 0)
{
buf[bytesRecv] = '\0';
std::cout << "Client " << clientId << " sent message: " << buf << std::endl;
// 广播消息给其他客户端
for (int i = 0; i < numClients; i++)
{
if (clients[i].socket != INVALID_SOCKET && clients[i].id != clientId)
{
send(clients[i].socket, buf, strlen(buf), 0);
}
}
}
// 客户端断开连接
std::cout << "Client " << clientId << " disconnected" << std::endl;
closesocket(clientSocket);
for (int i = 0; i < numClients; i++)
{
if (clients[i].socket == clientSocket)
{
clients[i].socket = INVALID_SOCKET;
break;
}
}
}
// 关闭服务器socket
closesocket(serverSocket);
// 清理Winsock库
WSACleanup();
return 0;
}
```
客户端:
```c++
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
// 初始化Winsock库
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR)
{
std::cerr << "Error: Failed to initialize Winsock library!" << std::endl;
return 1;
}
// 创建客户端socket
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET)
{
std::cerr << "Error: Failed to create client socket!" << std::endl;
WSACleanup();
return 1;
}
// 连接服务器
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddr.sin_port = htons(8888);
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
std::cerr << "Error: Failed to connect to server!" << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
// 登录
char username[256], password[256];
std::cout << "Enter username: ";
std::cin >> username;
std::cout << "Enter password: ";
std::cin >> password;
// 发送登录信息给服务器
char loginMsg[512];
sprintf(loginMsg, "LOGIN %s %s", username, password);
send(clientSocket, loginMsg, strlen(loginMsg), 0);
// 接收服务器消息
char buf[1024];
int bytesRecv;
while ((bytesRecv = recv(clientSocket, buf, sizeof(buf), 0)) > 0)
{
buf[bytesRecv] = '\0';
std::cout << "Server sent message: " << buf << std::endl;
}
// 关闭客户端socket
closesocket(clientSocket);
// 清理Winsock库
WSACleanup();
return 0;
}
```
以上代码只是一个简单的示例,还有很多细节需要完善,例如客户端的注册和登录验证、消息的格式等等。