Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 套接字:read()函数返回的长度不正确_Sockets - Fatal编程技术网

Sockets 套接字:read()函数返回的长度不正确

Sockets 套接字:read()函数返回的长度不正确,sockets,Sockets,我对套接字编程相当陌生。我的函数调用类似于: len = read(FD, buf, 1500); [负责从telnet连接读取数据] 下一行中的printf显示buf的长度大于300个字符,但intlen仅给出89个!因此,对返回字符串的所有进一步分析都将失败 我读过很多关于异步套接字读取返回的数据少于所需数据的问题,但在上述情况下,它返回了足够的数据,但报告的长度都是错误的[返回的字符串总是相同的,长度总是相同的错误值] 此外,当返回的字符串很小(通常在100个字符范围内)时,上述函数也能

我对套接字编程相当陌生。我的函数调用类似于:

len = read(FD, buf, 1500);
[负责从telnet连接读取数据]

下一行中的printf显示buf的长度大于300个字符,但intlen仅给出89个!因此,对返回字符串的所有进一步分析都将失败

我读过很多关于异步套接字读取返回的数据少于所需数据的问题,但在上述情况下,它返回了足够的数据,但报告的长度都是错误的[返回的字符串总是相同的,长度总是相同的错误值]

此外,当返回的字符串很小(通常在100个字符范围内)时,上述函数也能正常工作

任何指针都会非常有用


-Ashwin

通常对于异步套接字,您必须读取,直到收到所需的字节计数。这意味着您必须管理缓冲区。i、 e.根据接收到的字节等增加缓冲区指针


您观察到缓冲区的数据量正确,但报告的大小错误,这可能是由于上一次运行的过时数据造成的。确认您可以在每次运行之前清除缓冲区。

read尝试从文件描述符FD向缓冲区读取多达1500个字节,从buf开始。成功时,返回读取的字节数。如果该数字小于请求的字节数,则不是错误;这可能会发生,例如,因为现在实际可用的字节更少,可能是因为我们接近文件的结尾


通常,您需要在循环中调用读取。

您可以使用以下方法将缓冲区的读取偏移量归零:

buf[len] = 0;
打印通话应该正常

但在上述情况下,它返回了足够的数据,但报告的长度完全错误

不,你错了。它返回的是它所说的,它返回的是89字节。问题是,这89个字节不包含nul终止符,因此,当您打印缓冲区时,它会继续打印,在读取之前打印缓冲区其余部分中已经存在的内容

您应该做的,但请参见下面的警告:

len = read(FD, buf, 1500);
printf ("%*.*s\n", len, len, buf);
以确保打印不会超出缓冲区的末尾

你所看到的相当于:

char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Goodbye", 7);
printf ("%s", buff);
char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Go\0dbye", 8);
printf ("%s", buff);

               +---+---+---+---+---+---+---+---+---+---+---+---+
After sprintf: | H | e | l | l | o |   | t | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
After memcpy : | G | o | \0| d | b | y | e | \0| e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
因为您没有在memcpy中传输nul字符,所以剩下的缓冲区是:

               +---+---+---+---+---+---+---+---+---+---+---+---+
After sprintf: | H | e | l | l | o |   | t | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
After memcpy : | G | o | o | d | b | y | e | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
向弦道别

警告:

如果数据流中有nul字符,printf将无法工作,因为它将在找到的第一个nul字符处停止。read函数从文件描述符读取二进制数据,它不必在第一个换行符或nul字符处停止

这相当于:

char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Goodbye", 7);
printf ("%s", buff);
char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Go\0dbye", 8);
printf ("%s", buff);

               +---+---+---+---+---+---+---+---+---+---+---+---+
After sprintf: | H | e | l | l | o |   | t | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
After memcpy : | G | o | \0| d | b | y | e | \0| e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
放开绳子

如果您确实希望在二进制通道上处理以nul或换行符结尾的字符串,以下伪代码是一种方法:

while true:
    while buffer has no terminator character:
        read some more data into buffer, break on error or end-of-file.
    break on error or end-of-file.
    while buffer has at least one terminator character:
        process data up to first terminator character.
        remove that section from buffer.

这是一个读取数据的过程,直到你至少有一个工作单元,然后处理这些工作单元,直到你没有一个完整的工作单元。

你使用哪种语言/平台?您的printf失败,因为您的buf不是一个C字符串。89个有效字节后没有nul字符。它是一个在VxWorks平台上运行的用C编写的代码段。很抱歉没有提到这一点……这可能是代码中的一个错误,例如多次调用read来读取部分缓冲区,但只返回read的最终返回值。很抱歉延迟澄清:缓冲区中的数据实际上是telnet命令返回的数据。我通过手动远程登录到节点并在CLI中发出命令来验证这一点,该命令的响应也是由read命令收集的。这就是我所提到的,因为答复比报告的篇幅要长。同样,在前面提到的长度上,有一个规则的字母表,下一个字符也是一个字母表-因此不确定是否有特殊字符终止长度。响应肯定有换行符。正如我所说的printf%s,buf正确地打印了整个响应。所以我想中间没有/0。但是我们不能确定…@Ashwin,telnetd守护进程不太可能在流中或每行末尾发送nul字符,它实际上不是协议的一部分。因此,您真的应该依赖于行终止符字符,因为它是一个面向行的协议。这意味着,如果要将行传递给printf,或者按照我的回答使用length.length技巧,则需要终止行本身。您必须使用read的返回码来查找缓冲区的实际结尾,实际上没有其他方法。如果您确定流本身中不存在/0字符,那么在返回的buf上使用strlen如何?这可行吗?如果没有/0,我只是想知道为什么printf%s,buf首先会工作到适当的长度…在每次运行之前
memset buf,0,len已完成。正如我在下面的澄清中提到的,在每次发出命令时,内容都是正确的。它的数据是正确的,因为整个303字节的响应是正确的,一个89字节的响应在一个单词字典的中间截断,没有特殊的字符。响应只有303个字符长,但是我们要求1500字节。因为响应的长度是可变的。更大的问题是,我们在循环中运行read,直到找到一个结束分隔符字符串。其逻辑是在读取报告的长度内运行一个循环,并检查分隔符是否已预设。如果是,则终止读取循环。由于read报告的长度是错误的,所以所有的逻辑都会出错;首先读取X字节,然后在该长度的循环中请求读取。这是个好主意,但不幸的是,我正在Telnet的节点是第三方代码:-我必须确定是否可以找到添加长度头的方法,或者最终求助于对缓冲区进行strlen并使用它,而不是使用read函数的返回值…-有什么意见吗?有什么意见吗?像字符串的“\0”吗?