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;
    }
    
  • 相关阅读:
    SQL游标写法代码
    关键词过滤器
    TOP4NET20107027源代码非官方
    亚马逊API之订单下载
    PHP上传大文件参数设置
    CListCtrl中的一个错误(c++)
    汇编语言数据结构
    类型为“System.OutOfMemoryException”的异常
    【javascript脚本】动态设置div的高度和宽带
    【读书笔记】串指令备注
  • 原文地址:https://www.cnblogs.com/codeRhythm/p/14538381.html
Copyright © 2011-2022 走看看