Winsock - 如何同时接收和发送数据?

时间:2016-08-02 19:13:20

标签: c++ multithreading sockets networking winsock

我正在创建一个简单的聊天客户端,客户端加入服务器并向其发送消息,然后将消息发送给所有其他连接的客户端。

我遇到的问题是弄清楚如何让客户端能够向服务器发送消息,同时还能够通过服务器同时接收来自其他客户端的入站消息。我遇到的问题是,我发现输入的任何方法总是使线程挂起(因为它等待用户的输入)。

在收听传入数据时也是如此,但是我找到了一种方法来延迟等待,这样我就可以循环它,并在看到是否有任何数据需要再次处理之前做一些事情。 / p>

我的客户代码:

int main()
{
WSADATA wsaData;

SOCKET ConnectionSocket = INVALID_SOCKET;

addrinfo  *result = NULL;
addrinfo  hints;
addrinfo  *ptr    = NULL;

fd_set    set;

HANDLE    hThread;

string username;

unsigned  threadID;
int       iResult;
int       sent_msg;
int fileD;

char      send_buffer[DEFAULT_BUFLEN];
char      recieve_buffer[DEFAULT_BUFLEN];

bool      connected = true;

int       error_code;                

timeval   timeout_period;

/*
* Initalize WinSock.
*/
if (init_WinSock(wsaData)) { return 1; };

/*
* Zeroize structure.
*/
ZeroMemory(&hints, sizeof(hints));

hints.ai_family   = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

getaddrinfo("192.168.1.77", DEFAULT_PORT, &hints, &result);

ptr = result;

ConnectionSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

iResult = connect(ConnectionSocket, ptr->ai_addr, ptr->ai_addrlen);

freeaddrinfo(result);

if (iResult == SOCKET_ERROR) {
    error_code = WSAGetLastError();

    closesocket(ConnectionSocket);

    cout << "Unable to connect!";
    WSACleanup();
    system("Pause >> null");
    return 1;
}

cout << "Connected." << endl;
cout << "Please choose a username: ";

do {
    cin.getline(send_buffer, (int)strlen(send_buffer));

    if ((int)strlen(send_buffer) > 10) {
        cout << "Name too long! Choose again: ";
        memset(send_buffer, 0, DEFAULT_BUFLEN);
    }
} while ((int)strlen(send_buffer) > 10);

username = send_buffer;

/*
 * Initial connection. Send ID/username.
 */
send(ConnectionSocket, send_buffer, (int)strlen(send_buffer), 0);

memset(recieve_buffer, 0, DEFAULT_BUFLEN);

while (iResult != SOCKET_ERROR) {
    FD_ZERO(&set); /* clear the set */
    FD_SET(ConnectionSocket, &set);
    FD_SET(0, &set);

    error_code = select(ConnectionSocket + 1, &set, NULL, NULL, NULL);
    error_code = WSAGetLastError();

    if (FD_ISSET(0, &set)) {
        cin.getline(send_buffer, DEFAULT_BUFLEN);

        cout << username << ": " << send_buffer << endl;

        send(ConnectionSocket, send_buffer, DEFAULT_BUFLEN, 0);

        memset(send_buffer, 0, DEFAULT_BUFLEN);
    } else if (FD_ISSET(ConnectionSocket, &set)) {
        iResult = recv(ConnectionSocket, recieve_buffer, DEFAULT_BUFLEN, 0);
        recieve_buffer[iResult] = '\0';

        cout << "Placeholder: " << recieve_buffer << endl;

    }       
}

closesocket(ConnectionSocket);

cout << "\n\nDisconnected...";

system("pause >> null");

return 0;
}

服务器代码:

unsigned __stdcall handle_client(void *data)
{
    client_socket_data_type client;

    char                    recvbuf[DEFAULT_BUFLEN];

    timeval                 timeout_period;

    fd_set                  set;

    int iResult;

   // mutex                   mtx;

    client = *((client_socket_data_type *)data);

    memset(recvbuf, 0, DEFAULT_BUFLEN);

    timeout_period.tv_sec  = MAX_TIMEOUT;
    timeout_period.tv_usec = 0;

    FD_ZERO(&set); /* clear the set */
    FD_SET(client.client_socket, &set);

    iResult = select(client.client_socket, &set, NULL, NULL, &timeout_period);

    while (iResult != SOCKET_ERROR) {
        if (iResult > 0) {
            recv(client.client_socket, recvbuf, DEFAULT_BUFLEN, 0);

            if (recvbuf != " ") {
                for each (SOCKET connected_clients in client.connected_clients)
                {
                    if (client.client_socket != connected_clients) {
                        send(connected_clients, recvbuf, DEFAULT_BUFLEN, 0);
                        memset(recvbuf, 0, DEFAULT_BUFLEN);
                    }
                }
            }
        }
        iResult = select(client.client_socket, &set, NULL, NULL, &timeout_period);
    } 

    clients--;

    return 0;
}

int main()
{
    WSADATA wsaData;

    SOCKET    listen_socket = INVALID_SOCKET;
    SOCKET    client_socket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo  hints;

    client_socket_data_type client;

    HANDLE    hThread;

    unsigned  threadID;

    char recv_buffer[DEFAULT_BUFLEN];

    void *ctx;

    int error_code;
    int iResult;


    /*
    * Initalize WinSock.
    */
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    /*
    * Zeroize structure.
    */
    ZeroMemory(&hints, sizeof(hints));

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    listen_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (listen_socket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

   iResult = bind(listen_socket, result->ai_addr, (int)result->ai_addrlen);
   if (iResult == SOCKET_ERROR) {
       printf("bind failed with error: %d\n", WSAGetLastError());
       freeaddrinfo(result);
       closesocket(listen_socket);
       WSACleanup();
       return 1;
   }

    /*
    * Finished setup. Clear structure.
    */
    freeaddrinfo(result);

    /*
    * Listen on port for inbound connections.
    */
    iResult = listen(listen_socket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed with error: %d\n", WSAGetLastError());
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }

    cout << "Server initalized successfully. Waiting on client connections. 0/" << MAX_CLIENTS << endl;

    memset(recv_buffer, 0, DEFAULT_BUFLEN);

    while (true) {
        while (clients < MAX_CLIENTS) {
            client_socket = SOCKET_ERROR;

            while (client_socket == SOCKET_ERROR) {
                client_socket = accept(listen_socket, NULL, NULL);
            }

            client.client_socket = client_socket;

            clients++;

            cout << "Client connected. Number of connected clients: " << clients << '/' << MAX_CLIENTS << endl;

            /*
            * Initial connection. Asking for name.
            */

            recv(client.client_socket, recv_buffer, DEFAULT_BUFLEN, 0);

            cout << "Debug, name recieved. Name is: " << recv_buffer << endl;

            /*
            * Name put inside structure.
            */
            client.client_name = recv_buffer;

            ctx = &client;

            hThread = (HANDLE)_beginthreadex(NULL, 0, &handle_client, ctx, 0, &threadID);

            client.connected_clients.push_back(client.client_socket);

            memset(recv_buffer, 0, DEFAULT_BUFLEN);
        }
    }

    return 0;
}

0 个答案:

没有答案