【问题标题】:read handle problem读取句柄问题
【发布时间】:2011-06-21 03:54:46
【问题描述】:

我正在使用 epoll 进行网络编程,我有这段代码...

int read = read(socket, buf, bufsize);

我有一个巨大的缓冲区大小,我认为它会接收客户端发送的所有内容。 但是,我开始面临数据包分割等问题。

一个例子是,如果一个客户端发送了 500 字节,但它以某种方式进入了两个 250 字节的数据包,那么就没有办法处理这种情况。

我在网上查了一下,找到了这段代码

int handle_read(client *cli, struct epoll_event *ev) {
    size_t len = 4096;
    char *p;
    ssize_t received;

    cli->state = 1;
    if (cli->buffer != NULL) {
        //free(cli->buffer);
        //printf("Buff not null %s\n", cli->buffer);
    }

    //allocate space for data
    cli->buffer = (char*)malloc( (size_t)(sizeof(char) * 4096) );
    p = cli->buffer;

    do { //read until loop conditions
        received = recv(ev->data.fd, p, len, 0);
        if (received < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
            //if error, remove from epoll and close socket
            printf("Handle error!!!\nClient disconnected!\n");
            epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->data.fd, ev);
            close(ev->data.fd);
        }
        p = &cli->buffer[received];
    } while (received >= len && errno != EAGAIN && errno != EWOULDBLOCK);

    return received;
}

你们认为它可以处理接收时可能发生的所有异常吗?您还可以为我提供处理套接字异常的教程或示例吗?在线示例代码不包含详细信息.. 在此先感谢

【问题讨论】:

    标签: c++ sockets networking


    【解决方案1】:

    recv 可以返回三个中的任何一个,您的代码需要正确处理每一个:

    1) 正数。这意味着它读取了一些字节。

    2) 负数。这意味着发生了“错误”。

    3) 零。这意味着连接的另一端在套接字上执行了成功的shutdown()(或close())。 (通常,read() 或 recv() 返回 0 表示 EOF。)

    “错误”情况进一步分解为“EAGAINEWOULDBLOCK”和“其他所有情况”。前两个只是意味着它是一个非阻塞套接字,此时没有数据可以给你。您可能想返回并再次调用 poll()(或 select() 或 epoll())以避免忙于等待...

    “其他一切”表示真正的错误。你也需要处理这些;有关完整列表,请参阅 POSIX spec for recv()

    鉴于这一切,我会说您的示例代码很糟糕有几个原因。它不能正确处理 0(关闭连接)。它不处理任何错误。当recv() 返回EAGAIN/EWOULDBLOCK 时,它会执行繁忙循环。

    哦,它使用了sizeof(char),这表明它是由不熟悉 C 或 C++ 编程语言的人编写的。

    【讨论】:

    • 感谢您的回复。你知道任何好的示例代码或教程吗?我在网上看了,他们只介绍了一些基本的东西。提前致谢。
    • 不是随手...我总是自己动手。这是一个非常简单的嵌套 if/then 结构来处理所有情况,但是您希望如何处理每种情况的如何取决于特定的应用程序。 (特别是错误。你是返回代码还是抛出异常?嗯,这取决于你自己的约定。)
    • @user800799:不客气。你可以给我一个upvote :-)
    【解决方案2】:

    您通常无法知道“客户端发送了多少数据”。您应该使用可扩展的数据格式(在标题中具有数据长度)或数据标记的分隔符。例如,您可以在数据和下一个数据之间添加 \xff。或者,您应该使用固定的数据格式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多