zoukankan      html  css  js  c++  java
  • 网络编程基础_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;
    }
  • 相关阅读:
    智能移动机器人背后蕴含的技术——激光雷达
    Kalman Filters
    Fiddler抓HttpClient的包
    VSCode开发WebApi EFCore的坑
    WPF之小米Logo超圆角的实现
    windows react打包发布
    jenkins in docker踩坑汇总
    Using ML.NET in Jupyter notebooks 在jupyter notebook中使用ML.NET ——No design time or full build available
    【Linux知识点】CentOS7 更换阿里云源
    【Golang 报错】exec gcc executable file not found in %PATH%
  • 原文地址:https://www.cnblogs.com/ltyandy/p/10946009.html
Copyright © 2011-2022 走看看