zoukankan      html  css  js  c++  java
  • Windows下Socket服务器同时连接多客户端

    https://blog.csdn.net/yao_hou/article/details/102728970

    下面的代码是一个server对应多个client, 仅做测试demo, 如果是实际项目,需实际处理。

    编译脚本CMakeList.txt

    如果使用cmake编译,需要添加ws2_32库

    link_libraries(ws2_32)
    
    add_executable(select_client main.cpp)
    

    服务端代码

    服务器单线程启动,监听8000端口

    #include <winsock2.h>
    #include <iostream>
    
    using namespace std;
    
    int main() {
        // 初始化winsock的环境
        WSADATA wd;
        if (WSAStartup(MAKEWORD(2, 2), &wd) == SOCKET_ERROR) {
            cout << "WSAStartup  error:" << GetLastError() << endl;
            return 0;
        }
    
        // 1.创建监听套接字
        SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sListen == INVALID_SOCKET) {
            cout << "socket  error:" << GetLastError() << endl;
            return 0;
        }
    
        // 2.绑定到ip与端口
        sockaddr_in serverSockAddr;
        serverSockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        serverSockAddr.sin_port = htons(8000);
        serverSockAddr.sin_family = AF_INET;
        int len = sizeof(sockaddr_in);
        if (bind(sListen, (SOCKADDR *) &serverSockAddr, len) == SOCKET_ERROR) {
            cout << "bind  error:" << GetLastError() << endl;
            return 0;
        }
    
        // 3.监听套接字
        if (listen(sListen, 5) == SOCKET_ERROR) {
            cout << "listen  error:" << GetLastError() << endl;
            return 0;
        }
    
        // 4. select开始了
        fd_set readSet;//定义一个读(接受消息)的集合
        FD_ZERO(&readSet);//初始化集合
        FD_SET(sListen, &readSet);
    
        // 不停的select才可以读取套接字的状态改变
        while (true) {
            fd_set tmpSet; // 定义一个临时的集合
            FD_ZERO(&tmpSet); // 初始化集合
            tmpSet = readSet; // 每次循环都是所有的套接字
    
            // 利用select选择出集合中可以读写的多个套接字,有点像筛选
            int ret = select(0, &tmpSet, NULL, NULL, NULL);//最后一个参数为NULL,一直等待,直到有数据过来
            if (ret == SOCKET_ERROR) {
                continue;
            }
    
            // 成功筛选出来的tmpSet可以发送或者接收的socket
            for (int i = 0; i < tmpSet.fd_count; ++i) {
                //获取到套接字
                SOCKET selectedSocket = tmpSet.fd_array[i];
    
                // 接收到客户端的链接
                if (selectedSocket == sListen) {
                    SOCKET c = accept(selectedSocket, NULL, NULL);
                    // fd_set集合最大值为64
                    if (readSet.fd_count < FD_SETSIZE) {
                        //往集合中添加客户端套接字
                        FD_SET(c, &readSet);
                        cout << c << " logged in." << endl;
    
                        // 给客户端发送欢迎
                        char buf[100] = {0};
                        sprintf(buf, "hello from server", c);
                        send(c, buf, 100, 0);
                    } else {
                        cout << "max 64 clients for now." << endl;
                    }
    
                } else {
                    // 接收客户端的数据
                    char buf[100] = {0};
                    ret = recv(selectedSocket, buf, 100, 0);
                    if (ret == SOCKET_ERROR || ret == 0) {
                        closesocket(selectedSocket);
                        FD_CLR(selectedSocket, &readSet);
                        cout << selectedSocket << "logged off." << endl;
                    } else {
                        cout << selectedSocket << " sent " << buf << endl;
                    }
                }
            }
        }
    
        // 关闭监听套接字
        closesocket(sListen);
    
        // 清理winsock环境
        WSACleanup();
    
        return 0;
    }
    

    客户端启动,连接127.0.0.1:8000

    #include<winsock2.h>//winsock2的头文件
    #include<iostream>
    
    using namespace std;
    
    //勿忘,链接dll的lib
    #pragma comment(lib, "ws2_32.lib")
    
    int main() {
        //加载winsock2的环境
        WSADATA wd;
        if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
            cout << "WSAStartup  error:" << GetLastError() << endl;
            return 0;
        }
    
        //1.创建流式套接字
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == INVALID_SOCKET) {
            cout << "socket  error:" << GetLastError() << endl;
            return 0;
        }
    
        //2.连接服务器
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8000);
        addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        int len = sizeof(sockaddr_in);
        if (connect(s, (SOCKADDR *) &addr, len) == SOCKET_ERROR) {
            cout << "connect  error:" << GetLastError() << endl;
            return 0;
        }
    
        //3接收服务端的消息
        char buf[100] = {0};
        recv(s, buf, 100, 0);
        cout << buf << endl;
    
        //3随时给服务端发消息
        int ret = 0;
        do {
            char buf[100] = {0};
            cout << "Please input something:";
            cin >> buf;
            ret = send(s, buf, 100, 0);
        } while (ret != SOCKET_ERROR && ret != 0);
    
        //4.关闭监听套接字
        closesocket(s);
    
        //清理winsock2的环境
        WSACleanup();
    
        return 0;
    }
    
  • 相关阅读:
    398. Random Pick Index
    382. Linked List Random Node
    645. Set Mismatch
    174. Dungeon Game
    264. Ugly Number II
    115. Distinct Subsequences
    372. Super Pow
    LeetCode 242 有效的字母异位词
    LeetCode 78 子集
    LeetCode 404 左叶子之和
  • 原文地址:https://www.cnblogs.com/codeRhythm/p/14538381.html
Copyright © 2011-2022 走看看