• 网络编程基础_5.3聊天室-多人聊天室


    聊天室-多人聊天室

    #include <stdio.h>
    
    // 1. 包含必要的头文件和库, 必须位于 windows之前
    #include <WinSock2.h>
    #pragma comment(lib, "ws2_32.lib")
    
    #include <windows.h>
    #include <ws2tcpip.h>
    
    // 动态数组
    #include <vector>
    using namespace std;
    
    // 用于保存所有连接的客户端
    vector<SOCKET> ClientList;
    
    
    // 工具函数,用于判断是否执行成功
    VOID CheckResult(BOOL Value, LPCWSTR ErrMsg)
    {
        // 如果 Value 非空,就表示执行成功
        if (Value == FALSE)
        {
            printf("ErrMsg: %ls
    ", ErrMsg);
            system("pause"); ExitProcess(0);
        }
    }
    
    
    // 用于执行接收数据的线程
    DWORD WINAPI ThreadRoutine(LPVOID lpThreadParameter)
    {
        // 用于保存接收的数据
        CHAR Buffer[0x100] = { 0 };
    
        // 1. 获取到套接字的句柄
        SOCKET Socket = (SOCKET)lpThreadParameter;
    
        // 2. 在循环中不断的接收数据,如果返回值为 > 0 表示成功
        while (recv(Socket, Buffer, 0x100, 0) > 0)
        {
            // 转发给当前在线的除自己以外的所有客户端
            for (size_t i = 0; i < ClientList.size(); ++i)
            {
                // 排除掉自己,不会发消息给自己
                if (ClientList[i] == Socket)
                    continue;
    
                // 直接转发消息
                send(ClientList[i], Buffer, 0x100, 0);
            }
        }
    
        // 3. 将当前的套接字关闭并从列表移除
        for (int i = 0; i < ClientList.size(); ++i)
        {
            // 找到当前对应的套接字
            if (ClientList[i] == Socket)
            {
                // 收尾工作
                closesocket(Socket);
                printf("%08X 退出了聊天室
    ", Socket);
                ClientList.erase(ClientList.begin() + i);
                break;
            }
        }
    
        return 0;
    }
    
    int main()
    {
        // 2. 初始化网络环境并判断是否成功[ 搜索信号(2G?3G?4G?) ]
        WSAData WsaData = { 0 };
        if (!WSAStartup(MAKEWORD(2, 2), &WsaData))
            CheckResult(WsaData.wVersion == 0x0202, L"初始化网络环境失败");
    
        // 3. 创建套接字(IP+PORT) [ 买手机 ]
        SOCKET ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        CheckResult(ServerSocket != INVALID_SOCKET, L"套接字创建失败");
    
        // 4. 绑定套接字,提供IP和端口 (办手机卡)
        sockaddr_in ServerAddr = { 0 };
        ServerAddr.sin_port = htons(0x1515);        // 端口
        ServerAddr.sin_family = AF_INET;            // 协议类型
        inet_pton(AF_INET, "127.0.0.1", &ServerAddr.sin_addr.S_un);
        BOOL Result = bind(ServerSocket,    // 要绑定的套接字
            (SOCKADDR*)& ServerAddr,        // 服务器的地址和IP对应的结构体
            sizeof(sockaddr_in));            // 必须要指定大小
        CheckResult(Result != SOCKET_ERROR, L"套接字绑定失败");
    
        // 5. 监听套接字 (开机,等待连接)
        // -  监听谁,最多等待多少个客户端的链接
        Result = listen(ServerSocket, SOMAXCONN);
    
        // 6. 循环等待客户端的连接(接电话)
        while (true)
        {
            // 接收客户端
            int dwSize = sizeof(sockaddr_in);
            sockaddr_in ClientAddr = { 0 };        // 接收的客户端ip和端口
            SOCKET ClientSocket = accept(ServerSocket,
                (SOCKADDR*)& ClientAddr, &dwSize);
    
            // 添加到容器中
            printf("%08X 进入了聊天室
    ", ClientSocket);
            ClientList.push_back(ClientSocket);
    
            // 因为要接受每一个客户端发送的消息,所以需要分别创建线程
            CreateThread(NULL, NULL, ThreadRoutine, (LPVOID)ClientSocket, NULL, NULL);
        }
    
        // 9. 关闭套接字执行清理工作
        closesocket(ServerSocket);
    
        // 10. 清理网络环境
        WSACleanup();
    
        system("pause");
        return 0;
    }
  • 相关阅读:
    幸福必读
    JAVA程序员之路
    编写数据库操作类,使ASP.NET 中的数据库操作变得简单
    Duwamish 7.0 系列分析文章
    Visual Studio .NET加密技术剖析系列课程
    做为一个Tester,你为Testing付出了多少?
    程序员分成几种不同的境界
    深度探索C++对象模型(2).txt
    Eclipse快速上手指南之使用JUnit
    Eclipse使用技巧
  • 原文地址:https://www.cnblogs.com/ltyandy/p/10946009.html
Copyright © 2020-2023  润新知