Windows下用C++实现TCP, 服务器/客户端 "多人聊天室",客户端用户需要先注册再登陆,用户的注册信息保存在txt文件中,由服务器读取txt文件并接受用户客户端的连接,不能使用unistd.h库中的内容
时间: 2023-06-18 11:06:04 浏览: 120
C++实现基于云服务器多人聊天室项目源码,GUI界面实现客户端的登录与注册功能+聊天室功能
这是一个比较复杂的问题,需要涉及到网络编程、文件操作、多线程等多个方面。下面是一个简单的实现思路和代码示例,仅供参考。
1. 服务器端实现
服务器端需要监听指定的端口,并且能够接受多个客户端的连接。在接受客户端连接之后,需要创建一个新的线程来处理该客户端的请求,并且在主线程中继续监听其他客户端的连接。在处理客户端请求时,服务器需要实现以下功能:
- 注册:读取用户注册信息文件,检查用户名是否已经存在,如果不存在则将新用户信息保存到文件中。
- 登录:读取用户注册信息文件,检查用户名和密码是否正确,如果正确则向客户端发送登录成功的消息,并且将该客户端信息保存到一个列表中。
- 聊天:将客户端发送的消息广播给其他在线用户。
下面是一个简单的服务器端实现代码:
```cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include <stdexcept>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
const int MAX_CLIENTS = 10;
const int BUFFER_SIZE = 1024;
const string USER_FILE = "users.txt";
struct ClientInfo {
SOCKET socket;
string username;
ClientInfo(SOCKET s) : socket(s), username("") {}
};
vector<ClientInfo> clients;
mutex clients_mutex;
condition_variable clients_cv;
void handle_client(SOCKET client_socket) {
char buffer[BUFFER_SIZE];
int bytes_received;
string username;
bool logged_in = false;
while (true) {
// 接收客户端消息
bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (bytes_received == SOCKET_ERROR) {
cerr << "Error receiving data: " << WSAGetLastError() << endl;
break;
}
buffer[bytes_received] = '\0';
// 处理客户端消息
if (!logged_in) {
// 处理注册/登录请求
stringstream ss(buffer);
string command, name, password;
ss >> command >> name >> password;
if (command == "register") {
// 检查用户名是否已经存在
bool name_exists = false;
ifstream fin(USER_FILE);
string line;
while (getline(fin, line)) {
stringstream ss(line);
string n, p;
ss >> n >> p;
if (n == name) {
name_exists = true;
break;
}
}
fin.close();
// 如果用户名不存在,则将注册信息保存到文件中
if (!name_exists) {
ofstream fout(USER_FILE, ios::app);
fout << name << " " << password << endl;
fout.close();
username = name;
logged_in = true;
send(client_socket, "register success", strlen("register success"), 0);
} else {
send(client_socket, "register failure", strlen("register failure"), 0);
}
} else if (command == "login") {
// 检查用户名和密码是否正确
bool login_success = false;
ifstream fin(USER_FILE);
string line;
while (getline(fin, line)) {
stringstream ss(line);
string n, p;
ss >> n >> p;
if (n == name && p == password) {
login_success = true;
break;
}
}
fin.close();
// 如果登录成功,则保存客户端信息,并向客户端发送登录成功消息
if (login_success) {
username = name;
logged_in = true;
send(client_socket, "login success", strlen("login success"), 0);
} else {
send(client_socket, "login failure", strlen("login failure"), 0);
}
}
} else {
// 处理聊天消息
for (auto& c : clients) {
if (c.socket != client_socket) {
send(c.socket, (username + ": " + buffer).c_str(), strlen((username + ": " + buffer).c_str()), 0);
}
}
}
}
// 关闭客户端连接并从列表中删除该客户端
closesocket(client_socket);
unique_lock<mutex> lock(clients_mutex);
for (auto it = clients.begin(); it != clients.end(); ++it) {
if (it->socket == client_socket) {
clients.erase(it);
break;
}
}
clients_cv.notify_all();
}
int main() {
// 初始化Winsock
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
cerr << "Error initializing Winsock: " << result << endl;
return 1;
}
// 创建服务器套接字
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET) {
cerr << "Error creating server socket: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
// 绑定服务器套接字
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(1234);
result = bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr));
if (result == SOCKET_ERROR) {
cerr << "Error binding server socket: " << WSAGetLastError() << endl;
closesocket(server_socket);
WSACleanup();
return 1;
}
// 监听客户端连接
result = listen(server_socket, SOMAXCONN);
if (result == SOCKET_ERROR) {
cerr << "Error listening on server socket: " << WSAGetLastError() << endl;
closesocket(server_socket);
WSACleanup();
return 1;
}
// 循环接受客户端连接
while (true) {
// 接受客户端连接
sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
SOCKET client_socket = accept(server_socket, (sockaddr*)&client_addr, &client_addr_len);
if (client_socket == INVALID_SOCKET) {
cerr << "Error accepting client connection: " << WSAGetLastError() << endl;
break;
}
// 创建新线程处理客户端请求
thread t(handle_client, client_socket);
// 将客户端信息保存到列表中
unique_lock<mutex> lock(clients_mutex);
while (clients.size() >= MAX_CLIENTS) {
clients_cv.wait(lock);
}
clients.emplace_back(client_socket);
clients_cv.notify_all();
t.detach();
}
// 关闭服务器套接字
closesocket(server_socket);
// 清理Winsock
WSACleanup();
return 0;
}
```
2. 客户端实现
客户端需要向服务器发送注册/登录请求,并且能够接收其他用户的聊天消息。在接收聊天消息时,需要在界面上显示发送者的用户名和消息内容。客户端界面可以使用Windows API或者Qt等GUI库来实现。
下面是一个简单的客户端实现代码:
```cpp
#include <iostream>
#include <cstring>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
const int BUFFER_SIZE = 1024;
int main() {
// 初始化Winsock
WSADATA wsa_data;
int result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (result != 0) {
cerr << "Error initializing Winsock: " << result << endl;
return 1;
}
// 创建客户端套接字
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_socket == INVALID_SOCKET) {
cerr << "Error creating client socket: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
// 连接服务器
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(1234);
result = connect(client_socket, (sockaddr*)&server_addr, sizeof(server_addr));
if (result == SOCKET_ERROR) {
cerr << "Error connecting to server: " << WSAGetLastError() << endl;
closesocket(client_socket);
WSACleanup();
return 1;
}
// 读取用户输入并发送给服务器
char buffer[BUFFER_SIZE];
while (true) {
cin.getline(buffer, BUFFER_SIZE);
if (strlen(buffer) == 0) {
continue;
}
send(client_socket, buffer, strlen(buffer), 0);
// 接收服务器消息并显示在界面上
int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (bytes_received == SOCKET_ERROR) {
cerr << "Error receiving data: " << WSAGetLastError() << endl;
break;
}
buffer[bytes_received] = '\0';
cout << buffer << endl;
}
// 关闭客户端套接字
closesocket(client_socket);
// 清理Winsock
WSACleanup();
return 0;
}
```
阅读全文