为客户端添加输入线程

客户端:

#include<WinSock2.h>
#include<Windows.h>
#include<stdio.h>
//线程库头文件
#include<thread>


#pragma comment(lib,"ws2_32.lib")

enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_New_User_Join, CMD_ERROR };

//包头
struct DataHeader
{
    short dataLength;
    short cmd;
};
//包体
struct Login :public DataHeader
{
    Login()
    {
        dataLength = sizeof(Login);
        cmd = CMD_Login;
    }
    char username[32];
    char password[32];
};

struct LoginResult :public DataHeader
{
    LoginResult()
    {
        dataLength = sizeof(LoginResult);
        cmd = CMD_Login_Result;
        result = 0;
    }
    int result;
};

struct Logout :public DataHeader
{
    Logout()
    {
        dataLength = sizeof(Logout);
        cmd = CMD_Logout;
    }
    char username[32];
};

struct LogoutResult :public DataHeader
{
    LogoutResult()
    {
        dataLength = sizeof(LogoutResult);
        cmd = CMD_Logout_Result;
        result = 0;
    }
    int result;
};

struct NewUserJoin :public DataHeader
{
    NewUserJoin()
    {
        dataLength = sizeof(LogoutResult);
        cmd = CMD_New_User_Join;
        sock = 0;
    }
    int sock;
};

int process_solve(SOCKET _cSOCK)
{
    //增加一个缓冲区
    char szRecv[1024] = {};
    //5.接收客户端新数据
    int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), 0);
    DataHeader *header = (DataHeader*)szRecv;

    if (nLen <= 0)
    {
        printf("与服务器断开连接!任务结束!");
        return -1;
    }
    switch (header->cmd){
        case CMD_Login_Result:
        {
                recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
                LoginResult *loginresult = (LoginResult*)szRecv;
                printf("收到服务端消息请求:CMD_Login_Result,数据长度:%d
", loginresult->dataLength);
        }
        break;
        case CMD_Logout_Result:
        {
                recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
                LogoutResult* logoutresult = (LogoutResult*)szRecv;
                printf("收到服务端消息请求:CMD_Logout_Result,数据长度:%d
UserName:%s
", logoutresult->dataLength);
        }
        break;
        case CMD_New_User_Join:
        {
                recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
                NewUserJoin* newuserjoin = (NewUserJoin*)szRecv;
                printf("收到服务端消息请求:CMD_New_User_Join,数据长度:%d
UserName:%s
", newuserjoin->dataLength);
        }
        break;
    }
}

bool threadRun = true;
void cmdThread(SOCKET _sock)
{
    while (true)
    {
        char cmdBuf[256] = {};
        scanf("%s", cmdBuf);
        if (0 == strcmp(cmdBuf, "exit"))
        {
            threadRun = false;
            printf("退出!
");
            break;
        }
        else if (0 == strcmp(cmdBuf, "login"))
        {
            Login login;
            strcpy(login.username, "sutaoyu");
            strcpy(login.password, "sutaoyu01");
            send(_sock, (const char*)&login, sizeof(Login), 0);
        }
        else if (0 == strcmp(cmdBuf, "logout"))
        {
            Logout logout;
            strcpy(logout.username, "sutaoyu");
            send(_sock, (const char*)&logout, sizeof(Logout), 0);
        }
        else{
            printf("不支持的命令!");
        }
    }
    
}

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);

    //1.建立一个socket
    SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == _sock)
    {
        printf("ERROR:建立失败!
");
    }
    else{
        printf("客户端绑定成功......
");
    }
    //2.连接服务器
    sockaddr_in _sin = {};     //创建网络地址
    _sin.sin_family = AF_INET;
    _sin.sin_port = htons(4567); //Host to Network Short
    _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址 
    int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in));
    if (SOCKET_ERROR == ret)
    {
        printf("ERROR:连接失败!
");
    }
    else
    {
        printf("客户端连接成功......
");
    }

    //启动线程
    std::thread t1(cmdThread, _sock);
    t1.detach();
    while (threadRun)
    {
        //伯克利 socket
        fd_set fd_Read;
        FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据
        FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏
        timeval t = {1,0};
        int ret = select(_sock, &fd_Read, 0, 0,&t);
        if (ret < 0)
        {
            printf("select任务结束1!");
            break;
        }
        if (FD_ISSET(_sock,&fd_Read))
        {
            FD_CLR(_sock, &fd_Read);
            
            if (process_solve(_sock) == -1)
            {
                printf("select任务结束2!");
                break;
            }
        }

    }
    //7.关闭套接字
    closesocket(_sock);

    //WinSocket启动
    WSAStartup(ver, &dat);



    //WinSocket关闭
    WSACleanup();
    printf("已退出!");
    getchar();
    return 0;
}

服务器端:

#include<WinSock2.h>
#include<Windows.h>
#include<vector>
#include<stdio.h>
#include<iostream>


#pragma comment(lib,"ws2_32.lib")

enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_New_User_Join, CMD_ERROR };

//包头
struct DataHeader
{
    short dataLength;
    short cmd;
};
//包体
struct Login :public DataHeader
{
    Login()
    {
        dataLength = sizeof(Login);
        cmd = CMD_Login;
    }
    char username[32];
    char password[32];
};

struct LoginResult :public DataHeader
{
    LoginResult()
    {
        dataLength = sizeof(LoginResult);
        cmd = CMD_Login_Result;
        result = 0;
    }
    int result;
};

struct Logout :public DataHeader
{
    Logout()
    {
        dataLength = sizeof(Logout);
        cmd = CMD_Logout;
    }
    char username[32];
};

struct LogoutResult :public DataHeader
{
    LogoutResult()
    {
        dataLength = sizeof(LogoutResult);
        cmd = CMD_Logout_Result;
        result = 0;
    }
    int result;
};

struct NewUserJoin :public DataHeader
{
    NewUserJoin()
    {
        dataLength = sizeof(NewUserJoin);
        cmd = CMD_New_User_Join;
        sock = 0;
    }
    int sock;
};

std::vector<SOCKET> g_client;

int process_solve(SOCKET _cSOCK)
{
    //增加一个缓冲区
    char szRecv[1024] = {};
    //5.接收客户端新数据
    int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), 0);
    DataHeader *header = (DataHeader*)szRecv;

    if (nLen <= 0)
    {
        printf("客户端已退出!任务结束!");
        return -1;
    }
    switch (header->cmd){
    case CMD_Login:
    {
        recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
        Login *login = (Login*)szRecv;
        printf("收到客户端<Socket=%d>请求:CMD_Login,数据长度:%d
UserName:%s
PassWord:%s
", _cSOCK, login->dataLength, login->username, login->password);
        //忽略判断用户密码是否正确的过程
        LoginResult ret;
        send(_cSOCK, (char *)&ret, sizeof(LoginResult), 0); //再发消息体

    }
    case CMD_Logout:
    {

        recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
        Logout* logout = (Logout*)szRecv;
        printf("收到命令:CMD_Logout,数据长度:%d
UserName:%s
", logout->dataLength, logout->username);

        //忽略判断用户密码是否正确的过程
        LogoutResult let;
        send(_cSOCK, (char *)&let, sizeof(let), 0); //再发消息体
    }
        break;
    case CMD_New_User_Join:
    {

        recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
        NewUserJoin* UserJoin = (NewUserJoin*)szRecv;
        printf("收到命令:CMD_Logout,数据长度:%d
UserName:%s
", UserJoin->dataLength);

        //忽略判断用户密码是否正确的过程
        NewUserJoin let;
        send(_cSOCK, (char *)&let, sizeof(let), 0); //再发消息体
    }
        break;
    default:
    {
        DataHeader header = { 0 };
        send(_cSOCK, (char *)&header.cmd, sizeof(header), 0);
    }

        break;
    }
}

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    //WinSocket启动
    WSAStartup(ver, &dat);

    //1、建立一个socket
    SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP
    if (INVALID_SOCKET == _sock)
    {
        printf("ERROR:建立失败!
");
    }
    //2.绑定
    sockaddr_in _sin = {};     //创建网络地址
    _sin.sin_family = AF_INET;
    _sin.sin_port = htons(4567); //Host to Network Short
    _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址 
    if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR)
    {
        printf("ERROR:绑定失败!
");
    }
    else
    {
        printf("服务器端绑定成功......
");
    }
    //3.监听网络端口
    if (listen(_sock, 5) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接
    {
        printf("ERROR:监听失败!
");
    }
    else
    {
        printf("服务器端监听成功......
");
    }

    while (1)
    {
        //伯克利 socket
        fd_set fd_Read;
        fd_set fd_Write;
        fd_set fd_Exp;

        FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据
        FD_ZERO(&fd_Write);
        FD_ZERO(&fd_Exp);

        FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏
        FD_SET(_sock, &fd_Write);
        FD_SET(_sock, &fd_Exp);

        for (int n = g_client.size() - 1; n >= 0; n--)
        {
            FD_SET(g_client[n], &fd_Read);
        }

        /*
        select(
        _In_ int nfds,
        _Inout_opt_ fd_set FAR * readfds,
        _Inout_opt_ fd_set FAR * writefds,
        _Inout_opt_ fd_set FAR * exceptfds,
        _In_opt_ const struct timeval FAR * timeout
        );
        */

        //nfds是一个整数值,是指fd_set集合所有的描述符(select里的第一个参数)的范围(而不是数量)
        //既是所有文件描述符最大值+1
        timeval t = { 1, 0 };

        int ret = select(_sock + 1, &fd_Read, &fd_Write, &fd_Exp, &t);
        if (ret < 0)
        {
            printf("select任务结束!
");
            break;
        }
        if (FD_ISSET(_sock, &fd_Read))
        {
            FD_CLR(_sock, &fd_Read);
            //4.等待接收客户端连接
            sockaddr_in clientAddr = {};
            int nAddrLen = sizeof(sockaddr_in);
            SOCKET _cSOCK = INVALID_SOCKET;

            _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
            if (_cSOCK == INVALID_SOCKET)
            {
                printf("ERROR:无效客户端SOCKET!
");
            }
            for (int n = g_client.size() - 1; n >= 0; n--)
            {
                NewUserJoin UserJoin;
                send(g_client[n], (const char*)&UserJoin, sizeof(UserJoin), 0);
            }

            g_client.push_back(_cSOCK);
            printf("新客户端加入:Socket=%d,IP = %s
", (int)_cSOCK, inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串
        }
        for (int n = 0; n < fd_Read.fd_count; n++)
        {
            if (process_solve(fd_Read.fd_array[n]) == -1)
            {
                auto iter = find(g_client.begin(), g_client.end(), process_solve(fd_Read.fd_array[n]));
                if (iter != g_client.end())
                {
                    g_client.erase(iter);
                }
            }
        }
        printf("空闲时间处理其他业务.......
");
    }

    for (int n = g_client.size(); n >= 0; n--)
    {
        //8.关闭自身的socket
        closesocket(g_client[n]);
    }

    //8.关闭自身的socket
    closesocket(_sock);

    //WinSocket关闭
    WSACleanup();

    system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/zhuifeng-mayi/p/11001774.html