服务器
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <thread>
#include <mutex>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <sstream>
#include <random>
#include <chrono>
#include <algorithm>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8888
struct User {
std::string username;
std::string password;
std::string rank = "青铜";
};
std::unordered_map<std::string, User> users;
std::vector<std::tuple<SOCKET, std::string>> matchQueue; // 只保存 socket 和 username
std::mutex mtx;
std::vector<std::string> generateQuestions() {
std::vector<std::string> questions;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> num(1, 100);
std::uniform_int_distribution<> op(0, 3);
for (int i = 0; i < 10; ++i) {
int a = num(gen), b = num(gen);
int oper = op(gen);
char ops[] = {'+', '-', '*', '/'};
questions.push_back(std::to_string(a) + " " + ops[oper] + " " + std::to_string(b));
}
return questions;
}
void handleClient(SOCKET clientSocket) {
char buffer[1024];
int bytesReceived;
while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytesReceived] = '\0';
std::string request(buffer);
if (request.find("REGISTER") == 0) {
std::istringstream iss(request);
std::string cmd, username, password;
iss >> cmd >> username >> password;
if (users.find(username) != users.end()) {
std::string response = "REGISTER_FAIL 用户已存在";
send(clientSocket, response.c_str(), response.size(), 0);
} else {
User newUser;
newUser.username = username;
newUser.password = password;
users[username] = newUser;
std::string response = "REGISTER_SUCCESS 注册成功";
send(clientSocket, response.c_str(), response.size(), 0);
}
} else if (request.find("LOGIN") == 0) {
std::istringstream iss(request);
std::string cmd, username, password;
iss >> cmd >> username >> password;
if (users.find(username) != users.end() && users[username].password == password) {
std::string response = "LOGIN_SUCCESS " + username + " " + users[username].rank;
send(clientSocket, response.c_str(), response.size(), 0);
} else {
std::string response = "LOGIN_FAIL 登录失败";
send(clientSocket, response.c_str(), response.size(), 0);
}
} else if (request.find("MATCH") == 0) {
std::istringstream iss(request);
std::string cmd, username;
iss >> cmd >> username;
{
std::lock_guard<std::mutex> lock(mtx);
matchQueue.push_back(std::make_tuple(clientSocket, username));
std::cout << username << " 进入匹配队列,当前人数:" << matchQueue.size() << std::endl;
}
if (matchQueue.size() >= 2) {
SOCKET c1Socket, c2Socket;
std::string c1User, c2User;
{
std::lock_guard<std::mutex> lock(mtx);
c1Socket = std::get<0>(matchQueue[0]);
c1User = std::get<1>(matchQueue[0]);
c2Socket = std::get<0>(matchQueue[1]);
c2User = std::get<1>(matchQueue[1]);
matchQueue.erase(matchQueue.begin(), matchQueue.begin() + 2);
}
std::cout << "创建房间:" << c1User << " vs " << c2User << std::endl;
auto questions = generateQuestions();
// 向两个客户端发送题目
std::string qStr;
for (auto& q : questions) qStr += q + "|";
std::string msg = "QUESTIONS " + qStr;
send(c1Socket, msg.c_str(), msg.size(), 0);
send(c2Socket, msg.c_str(), msg.size(), 0);
// 接收两个客户端的成绩
char res1[1024], res2[1024];
recv(c1Socket, res1, sizeof(res1), 0);
recv(c2Socket, res2, sizeof(res2), 0);
std::istringstream iss1(res1), iss2(res2);
std::string cmd1, cmd2;
int correct1 = 0, correct2 = 0;
double time1 = 0.0, time2 = 0.0;
iss1 >> cmd1 >> correct1 >> time1;
iss2 >> cmd2 >> correct2 >> time2;
std::cout << c1User << " 正确数:" << correct1 << ",耗时:" << time1 << std::endl;
std::cout << c2User << " 正确数:" << correct2 << ",耗时:" << time2 << std::endl;
// 判定胜负
std::string result1 = "RESULT Win", result2 = "RESULT Lose";
if (correct1 < correct2 || (correct1 == correct2 && time1 > time2)) {
result1 = "RESULT Lose";
result2 = "RESULT Win";
}
send(c1Socket, result1.c_str(), result1.size(), 0);
send(c2Socket, result2.c_str(), result2.size(), 0);
// 关闭连接
closesocket(c1Socket);
closesocket(c2Socket);
}
}
}
closesocket(clientSocket);
}
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed.\n";
return 1;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed.\n";
WSACleanup();
return 1;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(PORT);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Bind failed.\n";
closesocket(serverSocket);
WSACleanup();
return 1;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "Listen failed.\n";
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "服务器已启动,正在监听端口 " << PORT << " ...\n";
while (true) {
sockaddr_in clientAddr;
int clientAddrLen = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrLen);
if (clientSocket != INVALID_SOCKET) {
std::cout << "客户端已连接。\n";
CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)handleClient, (LPVOID)clientSocket, 0, nullptr);
}
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
客户端
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <cmath> // 修正 abs -> std::abs
#include <chrono>
#include <thread>
#pragma comment(lib, "ws2_32.lib")
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024
SOCKET clientSocket;
// 解析服务器发来的题目
std::vector<std::string> parseQuestions(const std::string& data) {
std::vector<std::string> questions;
std::stringstream ss(data);
std::string item;
while (std::getline(ss, item, '|')) {
if (!item.empty()) questions.push_back(item);
}
return questions;
}
// 计算表达式(只支持 + - * /)
double evaluate(const std::string& expr) {
std::istringstream iss(expr);
double a, b;
char op;
iss >> a >> op >> b;
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return b != 0 ? a / b : 0;
default: return 0;
}
}
// 开始答题逻辑
void startQuiz(const std::vector<std::string>& questions) {
int correct = 0;
int totalAttempts = 0;
auto startTime = std::chrono::high_resolution_clock::now();
for (const auto& question : questions) {
int attempts = 0;
bool answered = false;
std::cout << "\n题目: " << question << std::endl;
while (!answered && attempts < 15) {
std::cout << "请输入答案(尝试次数: " << (15 - attempts) << "): ";
std::string userAnswer;
std::cin >> userAnswer;
// 简单验证
try {
double userAns = std::stod(userAnswer);
double correctAns = evaluate(question);
if (std::abs(userAns - correctAns) < 1e-6) { // 使用 std::abs
std::cout << "回答正确!\n";
correct++;
answered = true;
} else {
std::cout << "回答错误,正确答案是: " << correctAns << std::endl;
attempts++;
}
} catch (...) {
std::cout << "输入无效,请输入数字。\n";
attempts++;
}
}
if (!answered) {
std::cout << "本题失败,跳过。\n";
}
}
auto endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = endTime - startTime;
std::cout << "\n答题结束!共答对: " << correct << " 题,耗时: " << duration.count() << " 秒\n";
// 发送答题结果
std::string result = "RESULT " + std::to_string(correct) + " " + std::to_string(duration.count());
send(clientSocket, result.c_str(), result.size(), 0);
}
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed.\n";
return 1;
}
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed.\n";
WSACleanup();
return 1;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "连接失败.\n";
closesocket(clientSocket);
WSACleanup();
return 1;
}
std::cout << "连接服务器成功!\n";
char buffer[BUFFER_SIZE];
std::string username;
// 登录/注册循环
while (true) {
std::cout << "请选择操作: 1.注册 2.登录\n";
int choice;
std::cin >> choice;
std::string username, password;
std::cout << "请输入用户名: ";
std::cin >> username;
std::cout << "请输入密码: ";
std::cin >> password;
if (choice == 1) {
std::string regMsg = "REGISTER " + username + " " + password;
send(clientSocket, regMsg.c_str(), regMsg.size(), 0);
int bytes = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::string response(buffer);
std::cout << "服务器响应: " << response << std::endl;
if (response.find("REGISTER_SUCCESS") != std::string::npos) continue;
}
} else {
std::string loginMsg = "LOGIN " + username + " " + password;
send(clientSocket, loginMsg.c_str(), loginMsg.size(), 0);
int bytes = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::string response(buffer);
std::cout << "服务器响应: " << response << std::endl;
if (response.find("LOGIN_SUCCESS") != std::string::npos) {
std::istringstream iss(response);
std::string cmd, user, rank;
iss >> cmd >> user >> rank;
username = user;
break;
}
}
}
}
// 发送匹配请求
std::string matchMsg = "MATCH " + username;
send(clientSocket, matchMsg.c_str(), matchMsg.size(), 0);
std::cout << "等待匹配中...\n";
// 接收题目
int bytes = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::string request(buffer);
if (request.find("QUESTIONS") == 0) {
std::vector<std::string> questions = parseQuestions(request.substr(10));
startQuiz(questions);
}
}
// 接收胜负结果
bytes = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::string result(buffer);
std::cout << "比赛结果: " << result << std::endl;
}
closesocket(clientSocket);
WSACleanup();
return 0;
}