【问题标题】:How to make server ignores sent data from client after client get timeout on getting server response?客户端获取服务器响应超时后,如何使服务器忽略客户端发送的数据?
【发布时间】:2012-11-28 14:41:21
【问题描述】:

我正在使用带有 O_NONBLOCK 的套接字、选择、保持连接以及 HTTP 之类的东西。

每个服务器连接和客户端使用缓冲区来获取所有发送的数据,直到收到完整的消息

如何工作:

客户端发送数据“A”
客户端尝试接收来自服务器的响应
服务器收到但不立即回复
客户端超时
服务器发送响应“A”(但客户端现在没有收到)

另一个请求:

客户端发送数据“B”
服务器发送响应“B”
客户端只收到“AB”响应,而不是“B”

问题是客户端收到之前的缓冲区消息

源码如下:

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);
}

客户端代码是一个简单的带有超时的接收发送

知道怎么解决吗?

【问题讨论】:

  • 有什么问题?尝试重新定相。
  • @NikolaiNFetissov 问题是客户端收到之前的响应,添加了代码

标签: sockets client-server


【解决方案1】:

首先想到的是使客户端的超时时间足够大,以使客户端不会超时,除非服务器实际上已经死了……但我相信您已经想到了这一点。 :)

因此,假设这还不够好,接下来要尝试的是让客户端在它发送的每个请求中都发送一个 ID 号。 ID 号可以用一个简单的计数器生成(例如,对于客户端的第一个请求,它用 0 标记请求,第二个它用 1 标记它,等等)。服务器在发送回复时,会在回复中包含相同的 ID 号。

当客户端收到回复时,它会将回复数据中的 ID 号与其计数器的当前值进行比较。如果两个数字相同,则处理数据。如果不是,它会忽略数据。瞧!

【讨论】:

  • 如果没有其他解决方案将使用第二个选项,第一个选项不是一个好的解决方案,因为等待游戏响应的时间超过 6 秒(当前等待时间)可能非常耗时跨度>
  • 我想另一种方法是找出您的服务器响应时间如此之长的原因,并对其进行修复以使其响应更快...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 2020-08-16
  • 2014-10-31
  • 2018-12-02
相关资源
最近更新 更多