【问题标题】:TCP Sockets in C with bad networkC 语言中的 TCP 套接字,网络不好
【发布时间】:2017-01-24 17:59:13
【问题描述】:

我正在对 Raspberry Pi(PC 中的服务器)中的 TCP 客户端应用程序以及使用 LTE 调制解调器的 PPP(点对点协议)进行一些测试。我使用带有套接字的 C 程序,检查系统调用的响应。我想测试插座在覆盖范围不好的区域是如何工作的,所以我做了一些移除天线的测试。

我已按照以下步骤操作:

  1. 连接到服务器 --> OK
  2. 开始发送数据(写系统调用)--> OK(我也检查了服务器)
  3. 我移除了 LTE 调制解调器的天线(没有网络,无法 ping)
  4. 继续发送数据(write系统调用)--> OK服务器没有收到任何东西!!!
  5. 发送完数据并关闭socket --> OK(连接仍然打开,由于天线被移除没有数据)
  6. 程序已完成
  7. 我又放了天线

一段时间后,数据已上传,连接已关闭。但是我按照这个步骤做了另一个测试,但是有更多的数据,它没有上传这些数据......

不知道有没有什么办法可以保证写入TCP服务器的数据被服务器接收(我以为是TCP层保证了这一点..)。我可以使用 ACK 手动完成,但我想它必须是一种更好的方法。

发送部分代码:

    while(i<100)
    {
        sprintf(buf, "Message %d\n", i);
        Return = write(Sock_Fd, buf, strlen(buf));
        if(Return!=strlen(buf))
        {
            printf("Error sending data to TCP server. \n");
            printf("Error str: %s \n", strerror(errno));
        }
        else
        {
            printf("write successful %d\n", i);
            i++;
        }
        sleep(2);
    }

非常感谢您的帮助。

【问题讨论】:

  • 您使用的是非阻塞套接字吗?您如何编写数据并检查结果?能否请您尝试创建客户端程序的Minimal, Complete, and Verifiable Example 并展示给我们?
  • 我使用的是默认模式,我猜是阻塞模式(当我连接到服务器时,它会等待连接完成)。

标签: c sockets tcp


【解决方案1】:

write()-syscall 返回 true,因为内核会缓冲数据并将其放入套接字的出队列中。当数据被发送从对等方确认时,它会从这个队列中删除。当 OutQueue 已满时,write-syscall 将阻塞。

要确定数据是否未被对等方确认,您必须查看出队的大小。对于 linux,您可以为此使用 ioctl()

ioctl(fd, SIOCOUTQ, &outqlen);

但是,使用带内方法来确定是否已收到数据会更加简洁和便携。

【讨论】:

  • 什么是“带内方法”?我在google上查过,但没有找到任何明确的解释
  • @JulenUranga 这意味着确认是通过 tcp 连接本身发送的。客户端:“做某事” - 服务器:“完成”。
【解决方案2】:

TCP/IP 是相当原始的技术。互联网可能听起来很新,但这确实是古董。之所以需要 TCP,是因为 IP 几乎不提供任何保证,但 TCP 实际上并没有添加那么多保证。它的主要功能是将包协议变成流协议。这意味着 TCP 保证字节顺序;没有字节会乱序到达。不要指望更多。

您会看到 TCP 之上的协议添加了额外的检查。例如。 HTTP 有著名的 HTTP 错误代码,正是因为它不能依赖来自 TCP 的错误状态。您可能必须这样做 - 或者您可以考虑将您的服务实现为 HTTP 服务。 “RESTful”是指一种 API 设计方法,它紧跟 HTTP 哲学;这可能与您有关。

【讨论】:

    【解决方案3】:

    您的第 4 和第 5 个主题的简短答案是来自 this answer 的快捷方式(阅读完整答案以获取更多信息)

    一个socket有一个发送缓冲区,如果调用send()函数成功,并不意味着请求的数据真的被发送出去了,它仅仅意味着数据已经被添加到了发送缓冲区。对于 UDP 套接字,数据通常很快就会发送,如果不是立即发送的话,但是对于 TCP 套接字,在将数据添加到发送缓冲区和让 TCP 实现真正发送该数据之间可能存在相对较长的延迟。因此,当您关闭 TCP 套接字时,发送缓冲区中可能仍有待处理的数据,尚未发送,但您的代码认为它已发送,因为 send() 调用成功。如果 TCP 实现根据您的请求立即关闭套接字,那么所有这些数据都将丢失,您的代码甚至都不知道这一点。据说TCP是一个可靠的协议,像这样丢失数据并不是很可靠。这就是为什么仍然有数据要发送的套接字在您关闭它时会进入称为 TIME_WAIT 的状态。在这种状态下,它会一直等到所有待处理的数据都已成功发送或超时,在这种情况下,套接字将被强制关闭。

    内核在关闭套接字之前等待的时间, 无论它是否仍有待发送数据,都称为 逗留时间。

    顺便说一句:该答案还指docs,您可以在其中查看更多详细信息

    【讨论】:

    • “如果 TCP 实现在您请求时立即关闭套接字,所有这些数据都将丢失”。这是什么意思?服务器关闭连接还是客户端关闭套接字?还是两者兼而有之?
    • @JulenUranga 这意味着默认实现不会立即关闭连接:它会尝试发送缓冲区中仍然存在的所有数据(如果有)然后尝试关闭套接字优雅我> 。但是,如果您希望 立即 关闭套接字(例如,通过禁用 Linger Time),它将被关闭 forcefully,这意味着所有待处理的数据在缓冲区将被忽略并立即关闭连接。
    猜你喜欢
    • 2015-09-24
    • 2020-04-29
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多