在非阻塞的accetp成功后就创建一个线程来处理新的客户端,并将客户端socket和地址作为参数传给线程函数.

在非阻塞的代码中修改一下即可

 

示例代码:

/*
    主线程进行accpet,每次accpet成功后就生成一个线程处理这个连接过来的
    客户端
*/
#define WIN32_LEAN_AND_MEAN
#include<iostream>
#include<string>
#include<winsock2.h>

using namespace std;

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


DWORD WINAPI handleThreadProc(LPVOID param[])
{
    char recv_buffer[1024];
    char send_buffer[1024];
    int error_code;                //存储WSAGetLastError()的返回值
    int len = sizeof(SOCKADDR);
    SOCKET client_socket = (SOCKET)param[0];
    SOCKADDR_IN* client_addr=(SOCKADDR_IN*)param[1];
    //解决非阻塞的recv和send
    cout << "connect by " << inet_ntoa(client_addr->sin_addr) << ntohs(client_addr->sin_port) << endl;
    while (1)
    {
        memset(recv_buffer, '\0', 1024);
        //对于该函数,由于是非阻塞模式,没有数据不会阻塞,错误处理和上面类似
        if (recv(client_socket, recv_buffer, 1024, 0) == SOCKET_ERROR)
        {
            error_code = WSAGetLastError();
            if (error_code == WSAEWOULDBLOCK)
            {
                Sleep(100);
                continue;
            }
            else
            {
                cout << "recv error code is " << error_code << endl;
                closesocket(client_socket);
                WSACleanup();
                return -4;
            }
        }

        if (strcmp(recv_buffer, "quit") == 0)
        {
            cout << "客户端退出" << endl;
            closesocket(client_socket);
            return 1;
        }
        else
        {

            while (1)
            {
                cout << "recvice from  :" << inet_ntoa(client_addr->sin_addr) << ntohs(client_addr->sin_port)<<"\t" << recv_buffer << endl;
                cin >> send_buffer;
                if (send(client_socket, send_buffer, strlen(send_buffer) + 1, 0) == SOCKET_ERROR)
                {
                    error_code = WSAGetLastError();
                    if (error_code == WSAEWOULDBLOCK)
                    {
                        Sleep(200);
                        continue;
                    }
                    else
                    {
                        cout << "send error code is " << error_code << endl;
                        closesocket(client_socket);
                        return -5;
                    }
                }
                break;
            }
        }
    }
    return 1;
}
int main()
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))
    {
        cout << "版本错误, error code is " << WSAGetLastError() << endl;
        return 1;
    }



    ULONG noblock = 1;            //非阻塞参数
    SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKET client_socket;
    SOCKADDR_IN bind_addr;
    SOCKADDR_IN client_addr;
    LPVOID params[2];
    int error_code;                //存储WSAGetLastError()的返回值
    int len = sizeof(SOCKADDR);

    //设置非阻塞socket
    if (!ioctlsocket(server_socket, FIONBIO, &noblock))
    {
        cout << "设置非阻塞模式成功" << endl;
    }
    bind_addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
    bind_addr.sin_family = AF_INET;
    bind_addr.sin_port = htons(8889);

    //绑定ip和端口
    if (bind(server_socket, (sockaddr*)&bind_addr, len) == SOCKET_ERROR)
    {
        cout << "bind error code is " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    //开始监听
    if (listen(server_socket, 5) == SOCKET_ERROR)
    {
        cout << "listen error code is " << WSAGetLastError() << endl;
        WSACleanup();
        return -2;
    }

    //解决非阻塞的accpet
    while (1)
    {

        client_socket = accept(server_socket, (sockaddr*)&client_addr, &len);
        if (client_socket == INVALID_SOCKET)
        {
            error_code = WSAGetLastError();
            if (error_code == WSAEWOULDBLOCK)
            {
                Sleep(100);
                continue;
            }
            else
            {
                cout << "accept失败,错误码" << error_code << endl;
                continue;
            }
        }
        else
        {
            params[0] = (LPVOID)client_socket;
            params[1] = (LPVOID)&client_addr;
            CreateThread(0, 0, (LPTHREAD_START_ROUTINE)handleThreadProc, (LPVOID)params, 0, 0);
        }
        
    }

    return 0;
}