从Tcp客户端发送的数据接收非常缓慢

问题描述 投票:-1回答:1

我要做的系统有一台tcp服务器和大约1000个tcp客户端。每秒1000个客户端将数据发送到tcp服务器。为了模拟这种情况,首先我从一台PC上用以下代码连接了具有50个套接字的tcp服务器。

int main() {

    const char *hello = "Hello from client";

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
    serv_addr.sin_addr.s_addr = inet_addr("192.168.1.39");

    vector<int> vec;


    for ( uint8_t i = 0; i < 50; i++ ) {

        int sock =  socket(AF_INET, SOCK_STREAM, 0);
        if ( sock < 0 ) {
            cout << "... Cant Allocated Socket\n";
            return -1;
        }

        if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
        {
            cout << "... Connection Failed \n";
            return -1;
        }



        vec.push_back(sock);
    }

    for ( uint8_t i = 0; i < vec.size(); i++ ) {
        send(vec[i], hello, strlen(hello), 0);
        cout << "Message Send\n";
    }


    for ( uint8_t i = 0; i < vec.size(); i++ ) {
        shutdown(vec[i], 0);
        close(vec[i]);
    }
    return 0;
}

tcp客户端连接到tcp服务器后,它们将数据发送到tcp服务器并关闭套接字。我从终端看到,tcp客户端可以发送数据包而无需等待(少于10ms)

上面的tcp客户端代码可以成功工作,并将数据成功发送到tcp服务器。我用下面的tcp服务器代码显示来自tcp客户端的数据。

#define _DEF_TCP_SERVER_PORT                                        8080
#define _DEF_TCP_SERVER_MAX_QUEUE_LISTEN                            12

bool finish_app = false;

struct TcpClient {
    int clientSocket;
    struct in_addr clientAddr;
};
vector<TcpClient> TcpClients;


struct _ServiceTcpServer {
    bool enable;
    int sock;
    uint16_t connectedClient;
    uint32_t sockLen;
    sockaddr_in tcpServerAddr;
    sockaddr_in remoteAddr;
};

struct _ServiceTcpServer _serviceTcpServer;


void init_tcp_server_socket() {

    _serviceTcpServer.tcpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    _serviceTcpServer.tcpServerAddr.sin_family = AF_INET;
    _serviceTcpServer.tcpServerAddr.sin_port = htons(_DEF_TCP_SERVER_PORT);
    _serviceTcpServer.sockLen = sizeof(_serviceTcpServer.remoteAddr);

    int flag = 1;

    for ( ;; ) {
        _serviceTcpServer.sock = socket(AF_INET, SOCK_STREAM, 0);
        if ( _serviceTcpServer.sock < 0 ) {
            cout << "... Failed to allocate socket.\n";
            this_thread::sleep_for(chrono::seconds(1));
            continue;
        }

        if ( setsockopt(_serviceTcpServer.sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) ) {
            cout << "... Set SockOpt failed.\n";
            close(_serviceTcpServer.sock);
            this_thread::sleep_for(chrono::seconds(1));
            continue;
        }

        if( bind(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.tcpServerAddr, sizeof(_serviceTcpServer.tcpServerAddr)) == -1 ) {
            cout << "... Socket bind failed.\n";
            close(_serviceTcpServer.sock);
            this_thread::sleep_for(chrono::seconds(1));
            continue;
        }

        if ( listen(_serviceTcpServer.sock, _DEF_TCP_SERVER_MAX_QUEUE_LISTEN) != 0 ) {
            cout << "... Socket listen failed.\n";
            close(_serviceTcpServer.sock);
            this_thread::sleep_for(chrono::seconds(1));
            continue;
        }

        break;

    }


    cout << "Socket init done \n";
}

void tcp_user_accept_task() {

    while ( finish_app == false ) {
        int temp_sck = -1;
        temp_sck = accept(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.remoteAddr, &_serviceTcpServer.sockLen);
        if ( temp_sck == -1 ) {
            this_thread::sleep_for(chrono::seconds(2));
            continue;
        }
        TcpClient tcpClient;
        tcpClient.clientAddr = _serviceTcpServer.remoteAddr.sin_addr;
        tcpClient.clientSocket = temp_sck;
        TcpClients.push_back( tcpClient );
        cout << "... New connection request: " << temp_sck << endl;
        ++_serviceTcpServer.connectedClient;
        this_thread::sleep_for(chrono::milliseconds(50));
    }
}


uint8_t temp_recv[100];
void tcp_server_run() {

    while ( finish_app == false ) {

        for(uint16_t i = 0 ; i < _serviceTcpServer.connectedClient; i++ ) {
            int temp_cs = TcpClients[i].clientSocket;
            fcntl(temp_cs, F_SETFL, O_NONBLOCK);
            int temp_recvLen  = recv(temp_cs, temp_recv, 20, 0);
            if( temp_recvLen > 0 ) {
                time_t _time = chrono::system_clock::to_time_t(chrono::system_clock::now());
                cout << "Message Received At:" << ctime(&_time) << "   :";
                cout << temp_recv << endl;
                break;
            } else {
                this_thread::sleep_for(chrono::milliseconds(10));
            }
        }

        if ( temp_recv[0] == 'q' ) {
            finish_app = true;
        }
    }

    close(_serviceTcpServer.sock);
}




int main() {

    thread init_thread(init_tcp_server_socket);
    init_thread.join();
    thread accept_thread(tcp_user_accept_task);
    thread run_thread(tcp_server_run);
    accept_thread.join();
    run_thread.join();

    return 0;
}

但是问题是,如屏幕图像所示,仅在1秒钟内收到了大约3-4个数据包。

enter image description here

c++ linux tcp tcpclient tcpserver
1个回答
0
投票

您应该同时接收套接字,而不是查询每个套接字并在每次尚未准备好数据时休眠10ms。

正确的方法取决于平台

  • posix-选择

  • Linux-民意调查,epoll,io_submit

  • windows-I / O完成端口

通常,选择哪个是posix标准将足以满足您的需求。如果您想要多平台,则可能还需要探索第三方库,例如libeventlibev,这些库已经为您包装了这些平台depent调用。

快乐编码!

© www.soinside.com 2019 - 2024. All rights reserved.