0

O_NONBLOCK、select、keep alive接続、およびHTTPなどのソケットを使用しています。

各サーバー接続とクライアント側は、完全なメッセージが受信されるまで、バッファを使用して送信されたすべてのデータを取得します

作業方法:

クライアントはデータ「A」を送信
しますクライアントはサーバーから応答を受信しようとします
サーバーは受信しますがすぐには応答しません
クライアントはタイムアウトを取得し
ますサーバーは応答「A」を送信します(ただしクライアントは今は受信しません)

別のリクエスト:

クライアントはデータ「B」
を送信しますサーバーは応答「B」を送信し
ますクライアントは「B」のみの代わりに「AB」応答を受信します

問題は、クライアントが以前のバッファメッセージを受信することです

以下のソースコード:

Server.cpp基本クラス:

bool Server::start()
{
    struct sockaddr_in client_addr;
    SOCKET client_socket, max_sock;
    Connection* conn;
    int addrlen = sizeof(struct sockaddr_in);
    std::list<Connection*>::iterator it, itr;
    int response;
    fd_set fdset, read_fds;

    max_sock = m_socket;
    FD_ZERO(&fdset);
    FD_SET(m_socket, &fdset);
    onStart();

    while(true)
    {
        // make a copy of set
        read_fds = fdset;
        // wait for read event
        response = select(max_sock + 1, &read_fds, NULL, NULL, NULL);
        if(response == -1)
            break;
        // check for new connections
        if(FD_ISSET(m_socket, &read_fds))
        {
            response--;
            // accept connections
            client_socket = accept(m_socket, (struct sockaddr*)&client_addr, &addrlen);
            if(client_socket != INVALID_SOCKET)
            {
                conn = new Connection(*this, client_socket, &client_addr);
                m_connections.push_front(conn);
                // add connection to set for wait for read event
                FD_SET(client_socket, &fdset);
                // allow select new sock from select funcion
                if(max_sock < client_socket)
                    max_sock = client_socket;
            }
        }
        // check for received data from clients
        it = m_connections.begin();
        while(it != m_connections.end() && response > 0)
        {
            conn = *it;
            // verify if connection can be readed
            if(FD_ISSET(conn->getSocket(), &read_fds))
            {
                response--;
                conn->receive();
                if(!conn->isConnected())
                {
                    FD_CLR(conn->getSocket(), &fdset);
                    // remove connection from list
                    itr = it;
                    it++;
                    m_connections.erase(itr);
                    delete conn;
                    continue;
                }
            }
            it++;
        }
    }
    onFinish(response >= 0);
    return response >= 0;
}

main.cppサーバーの実装:

void ClientConnection::onReceive(const void * data, size_t size)
{
    const char *str, *pos = NULL;
    HttpParser* p;

    buffer->write(data, size);
    do
    {
        str = (const char*)buffer->data();
        if(contentOffset == 0)
        {
            pos = strnstr(str, buffer->size(), "\r\n\r\n");
            if(pos != NULL)
            {
                contentOffset = pos - str + 4;
                p = new HttpParser((const char*)buffer->data(), contentOffset);
                contentLength = p->getContentLength(); 
                delete p;
            }
        }
        if(buffer->size() - contentOffset < contentLength || contentOffset == 0)
            return;
        proccessRequest();
        keepDataStartingOf(contentOffset + contentLength);
    }
    while(buffer->size() > 0);
}

クライアント側のコードは、タイムアウト付きの単純なrecv送信です

解決する方法はありますか?

4

1 に答える 1

0

最初に頭に浮かぶのは、クライアントのタイムアウトを十分に大きくして、サーバーが実際に停止しない限りクライアントがタイムアウトしないようにすることです...しかし、あなたはすでにそれを考えていると思います. :)

それで十分な修正ではないと仮定すると、次に試みることは、クライアントが送信する各リクエストで ID 番号を送信することです。ID 番号は単純なカウンターで生成できます (たとえば、クライアントの最初の要求の場合は要求に 0 をタグ付けし、2 番目の要求には 1 をタグ付けするなど)。サーバーは、応答を送信するときに、同じ ID 番号を応答に含めます。

クライアントが応答を受信すると、応答データ内の ID 番号をそのカウンターの現在の値と比較します。2 つの数値が同じ場合、データを処理します。そうでない場合、データは無視されます。出来上がり!

于 2012-12-13T04:43:03.160 に答える