导航菜单

项目实战

通过实际项目学习C++网络编程和多线程应用

90%
多人聊天室实现

聊天室服务器

使用TCP实现多人聊天室功能。

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
using namespace std;

class ChatServer {
private:
    int serverSocket;
    vector<int> clientSockets;
    mutex clientsMutex;
    
    // 广播消息给所有客户端
    void broadcast(const string& message, int excludeSocket = -1) {
        lock_guard<mutex> lock(clientsMutex);
        for (int clientSocket : clientSockets) {
            if (clientSocket != excludeSocket) {
                send(clientSocket, message.c_str(), message.length(), 0);
            }
        }
    }
    
    // 处理单个客户端
    void handleClient(int clientSocket) {
        char buffer[1024];
        string welcomeMsg = "欢迎加入聊天室!";
        send(clientSocket, welcomeMsg.c_str(), welcomeMsg.length(), 0);
        
        while (true) {
            memset(buffer, 0, sizeof(buffer));
            int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
            
            if (bytesRead <= 0) {
                // 客户端断开连接
                {
                    lock_guard<mutex> lock(clientsMutex);
                    auto it = find(clientSockets.begin(), clientSockets.end(), clientSocket);
                    if (it != clientSockets.end()) {
                        clientSockets.erase(it);
                    }
                }
                string disconnectMsg = "一个用户离开了聊天室";
                broadcast(disconnectMsg, clientSocket);
                close(clientSocket);
                break;
            }
            
            // 广播消息
            string message = string(buffer);
            broadcast(message, clientSocket);
        }
    }

public:
    ChatServer(int port) {
        serverSocket = socket(AF_INET, SOCK_STREAM, 0);
        if (serverSocket == -1) {
            throw runtime_error("创建socket失败");
        }
        
        sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(port);
        serverAddr.sin_addr.s_addr = INADDR_ANY;
        
        if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
            throw runtime_error("绑定失败");
        }
        
        if (listen(serverSocket, 5) < 0) {
            throw runtime_error("监听失败");
        }
        
        cout << "聊天室服务器启动,监听端口 " << port << endl;
    }
    
    void start() {
        while (true) {
            sockaddr_in clientAddr;
            socklen_t clientLen = sizeof(clientAddr);
            
            int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen);
            if (clientSocket < 0) {
                cerr << "接受连接失败" << endl;
                continue;
            }
            
            {
                lock_guard<mutex> lock(clientsMutex);
                clientSockets.push_back(clientSocket);
            }
            
            // 为新客户端创建线程
            thread clientThread(&ChatServer::handleClient, this, clientSocket);
            clientThread.detach();
            
            string newUserMsg = "新用户加入聊天室";
            broadcast(newUserMsg, clientSocket);
        }
    }
    
    ~ChatServer() {
        close(serverSocket);
    }
};