C语言:int读取不完整

3
我有一个程序,它分配了一个32位int,并尝试使用read(2)从套接字中读取4个字节到该int中。 有时候读取是不完整的,可能只读了2个字节。有没有什么方法可以从这种情况中恢复?我想我必须在int的中间产生一个指针以进行另一次读取。 你应该如何处理这种情况?我能想象出一些丑陋的方法,但没有优雅的方法。

5
在C语言中处理序列化确实很麻烦。 - Eugene Sh.
也许我误解了,但您能先读取所有四个字节,然后再对它们进行反序列化吗?请注意,如果您关心大小端,则应该无论如何都这样做。 - Patrick87
2
@EugeneSh。处理序列化很丑陋.. FTFY - Patrick87
@Patrick87:是的,也许我必须这样做。但我觉得问题本身很有趣,想看看是否还有其他方法。 - Alexander Torstling
3个回答

3

首先,您需要确保已经读取了4个字节。您可以使用类似于此函数(稍作修改)来完成这个操作:

#include <sys/types.h>
#include <sys/socket.h>

int readall(int s, char *buf, int *len)
{
    int total = 0;        // how many bytes we've read
    int bytesleft = *len; // how many we have left to read
    int n = -1;

    while(total < *len) {
        n = read(s, buf+total, bytesleft, 0);
        if (n <= 0)  { break; }  
        total += n;
        bytesleft -= n;
    }

    *len = total; // return number actually read here

    return (n<=0)?-1:0; // return -1 on failure, 0 on success
} 

之后,您可以使用这四个字节来组合一个整数。

1
你还需要在 n == 0 处中断,否则你将会在流的末尾无限循环。 - user207421
@EJP:当返回值为0时,可能在下一次接收时读取到某些内容,这种情况是无效的。 - Giorgi Moniava
我认为在我们的答案中忽略超时是合理的;在现实生活中,我们希望使用超时来查看我们是否在合理的时间内获取所请求的数据。如果我们期望4个字节并调用读取操作却得到0,则我个人仍会等待超时。 - Patrick87
谢谢。你其实不必贴出那么多代码,我只是想知道将int作为缓冲区是否可行以及如何处理恢复的情况。我猜你的意思是不行,但能否详细说明一下原因呢?难道没有一种通用的方法来将int视为字节缓冲区吗? - Alexander Torstling
@AlexanderTorstling:你可以将char指针转换为int类型,并根据接收到的字节数进行偏移,只有当读取完所有4个字节时才考虑完成。 - Giorgi Moniava
显示剩余12条评论

0

免责声明:这是糟糕的代码。不要这样做。

int value = 0;
int bytes = 0;
while ( (bytes += read(((char*)&value)+bytes, 4-bytes)) < 4 );

4
我同意。不要发布它。 - user207421
@EJP 根据评论给他想要的东西。我不关心他坚持用绳子做什么。 - Patrick87

0

通过这里的信息和在C/C++中添加1个字节的正确方法是什么?,我得出以下结论:

  1. 在某些架构上,将地址转换为int可能会导致对齐问题。
  2. 您可以尝试使用类型转换(将intchar[]联合起来),但实际上,这种技术似乎并不比1更可靠。
  3. 唯一真正可移植的字节指针算术方式是使用char[]中的char*。因此,处理此情况的正确方法是将所有字节读入数组中,并在之后构造int。
  4. 可以通过ntohl或位移进行重构为int。位移在主机机器字节顺序之间是可移植的,因为它是根据乘法定义的
那么,这让我们怎么办呢?好吧,可移植的选择是读入一个char[],然后通过位移或ntohl重构。非可移植的方法是像@Patrick87建议的那样将char *指向您的int。
我选择了务实的道路,只是创建了一个char*指向我的int。在我的目标平台上运行良好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接