0

当我尝试仅使用 1 个客户端连接到服务器时,recv()服务器上的功能不会延迟。

但是,当我启动客户端控制台超过 1 次(大约 7 次)时,在您使用该功能将数据包发送到服务器后,会有大约 2000 毫秒的延迟,send()直到服务器将数据包打印到控制台中。

有没有为每个客户端启动线程的解决方案?(Windows 限制每个进程的线程数)。

该代码使用 Visual Studio 2008 编译,这是完整的服务器代码:

#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>

struct sslv3
{
#define max_clients 1024
private:
    int cClient;
public:
    SOCKET fd;
    int CurrentClient()
    {
        return cClient;
    }
    struct client
    {
        client()
        {
            Valid = false;
        }
        bool Valid;
        DWORD ip;
        WORD port;
        char ipstr[33];
        char portstr[33];
        SOCKET fd;
        void StrGen()
        {
            wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
            wsprintf(portstr, "%d", port);
        }
    } clients[max_clients];
    //
    sslv3(bool server_client)
    {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
        cClient = 0;
        fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        //
        DWORD timeout = 1;
        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
    }
    int Bind(WORD port)
    {
        int ret = 0;
        sockaddr_in local;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
            != SOCKET_ERROR)
            listen(fd, SOMAXCONN);
        return ret;
    }
    int Accept()
    {
        SOCKET clientfd;
        sockaddr_in client;
        int addrlen = sizeof(client);
        clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
        if(clientfd == -1)
            return -1;
        clients[cClient].ip = client.sin_addr.S_un.S_addr;
        clients[cClient].port = client.sin_port;
        clients[cClient].StrGen();
        clients[cClient].fd = clientfd; 
        clients[cClient].Valid = true;
        //
        DWORD timeout = 1;
        setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
        cClient++;
        if(cClient >= max_clients)
        {
            cClient = 0;
            return max_clients - 1;
        }
        return cClient - 1;
    }
    int Connect(char ip[], WORD port)
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(ip);
        addr.sin_port = htons(port);
        return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
    }
    int Send(SOCKET sfd, void* buffer, int length)
    {
        return send(sfd, (char*)buffer, length, 0);
    }
    int Read(SOCKET sfd, void* buffer, int length)
    {
        return recv(sfd, (char*)buffer, length, 0);
    }
};

sslv3 cssl(true);

DWORD WINAPI ReadThread(void* args)
{
    while(true)
    {
        for(int j = 0; j <= cssl.CurrentClient(); j++)
        {
            if(cssl.clients[j].Valid)
            {
                char rpack[1024];
                for(int i = 0; i < sizeof(rpack); i++)
                    rpack[i] = 0;
                if(cssl.Read(cssl.clients[j].fd, rpack, sizeof(rpack)) > 0){
                    printf("%s:%s says: %s\n", cssl.clients[j].ipstr, cssl.clients[j].portstr, rpack);
                }
            }
        }
        Sleep(1);
    }
    return TRUE;
}

int main()
{
    cssl.Bind(1234);
    CreateThread(0,0,ReadThread,0,0,0);
    while(true)
    {
        Sleep(1);
        int cid = cssl.Accept();
        if(cid != -1){
            printf("%s:%s connected!\n", cssl.clients[cid].ipstr, cssl.clients[cid].portstr);
        }
    }
    return 0;
}

以下是完整的客户端代码:

#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>

#include <iostream>
using namespace std;

struct sslv3
{
#define max_clients 1024
private:
    int cClient;
public:
    SOCKET fd;
    int CurrentClient()
    {
        return cClient;
    }
    struct client
    {
        client()
        {
            Valid = false;
        }
        bool Valid;
        DWORD ip;
        WORD port;
        char ipstr[33];
        char portstr[33];
        SOCKET fd;
        void StrGen()
        {
            wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
            wsprintf(portstr, "%d", port);
        }
    } clients[max_clients];
    //
    sslv3(bool server_client)
    {
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
        cClient = 0;
        fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        //
        DWORD timeout = 1;
        setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
    }
    int Bind(WORD port)
    {
        int ret = 0;
        sockaddr_in local;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
            != SOCKET_ERROR)
            listen(fd, SOMAXCONN);
        return ret;
    }
    int Accept()
    {
        SOCKET clientfd;
        sockaddr_in client;
        int addrlen = sizeof(client);
        clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
        if(clientfd == -1)
            return -1;
        clients[cClient].ip = client.sin_addr.S_un.S_addr;
        clients[cClient].port = client.sin_port;
        clients[cClient].StrGen();
        clients[cClient].fd = clientfd; 
        clients[cClient].Valid = true;
        //
        DWORD timeout = 1;
        setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
        cClient++;
        if(cClient >= max_clients)
        {
            cClient = 0;
            return max_clients - 1;
        }
        return cClient - 1;
    }
    int Connect(char ip[], WORD port)
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(ip);
        addr.sin_port = htons(port);
        return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
    }
    int Send(SOCKET sfd, void* buffer, int length)
    {
        return send(sfd, (char*)buffer, length, 0);
    }
    int Read(SOCKET sfd, void* buffer, int length)
    {
        return recv(sfd, (char*)buffer, length, 0);
    }
};

sslv3 cssl(false);

int main()
{
    cssl.Connect("127.0.0.1", 1234);
    while(true)
    {
        printf("say: ");
        char buf[1024];
        for(int i = 0; i < sizeof(buf); i++)
            buf[i] = 0;
        cin >> buf;
        int len = strlen(buf);
        cssl.Send(cssl.fd, buf, len);
    }
    return 0;
}
4

1 回答 1

0

服务器似乎“空闲”了 2 秒,因为一些客户端在 2 秒后处理sleep,每个客户端 1 秒。

这显然不是在服务器上处理多个客户端的正确方法。您可能需要检查参考select()

一个非常好的socket编程教程是Beej的

于 2013-02-12T11:24:20.330 回答