从sockets读取

我需要使用从C read的函数从AF_UNIX套接字读取到缓冲区,但我不知道缓冲区大小。

我认为最好的方法是读取N个字节,直到读取返回0 (套接字中不再有写入器)。 它是否正确? 有没有办法猜测套接字上写入的缓冲区的大小?

我以为socket是一个特殊的文件。 以二进制模式打开文件并获取大小将有助于我知道给缓冲区的正确大小?

我是C的新手,所以请记住这一点。

常见的方法是使用ioctl(..)查询套接字的FIONREAD ,它将返回可用的数据量。

 int len = 0; ioctl(sock, FIONREAD, &len); if (len > 0) { len = read(sock, buffer, len); } 

在避免阻塞的同时从套接字读取未知量的一种方法是轮询()非阻塞套接字以获取数据。

例如

 char buffer[1024]; int ptr = 0; ssize_t rc; struct pollfd fd = { .fd = sock, .events = POLLIN }; poll(&fd, 1, 0); // Doesn't wait for data to arrive. while ( fd.revents & POLLIN ) { rc = read(sock, buffer + ptr, sizeof(buffer) - ptr); if ( rc <= 0 ) break; ptr += rc; poll(&fd, 1, 0); } printf("Read %d bytes from sock.\n", ptr); 

我认为最好的方法是读取N个字节,直到读取返回0(套接字中不再有写入器)。 它是否正确?

0表示EOF,另一侧表示已关闭连接。 如果通信的另一方关闭连接,那么它是正确的。

如果连接未关闭(通过相同的连接,chatty协议进行多次传输),则情况会更复杂,并且行为通常取决于您是否具有SOCK_STREAM或SOCK_DGRAM套接字。

操作系统已经为您分隔了数据报套接字。

流套接字不分隔消息(所有数据都是不透明的字节流),如果需要,必须在应用程序级别实现它:例如,通过在消息头结构中定义大小字段或使用分隔符(例如’\ n’代表单行短信)。 在第一种情况下,您将首先读取标题,提取长度并使用长度读取消息的其余部分。 在其他情况下,读取流到部分缓冲区,搜索分隔符并从缓冲区中提取包含分隔符的消息(您可能需要保留部分缓冲区,因为依赖于协议,可以使用单个recv()/ read接收多个命令( ))。

有没有办法猜测套接字上写入的缓冲区的大小?

对于流套接字,没有可靠的方法,因为通信的另一端可能仍在处理数据。 想象一下非常正常的情况:套接字缓冲区是32K,正在写入128K。 编写应用程序将阻塞send()/ write()内部,等待读取应用程序的OS读出数据,从而为下一块写入数据释放空间。

对于数据报套接字,通常可以预先知道消息的大小。 或者可以尝试(从未自己做过)recvmsg(MSG_PEEK),如果MSG_TRUNC位于返回的msghdr.msg_flags中,请尝试增加缓冲区大小。

你是对的,如果你不知道输入的大小,你每次只能读取一个字节并将其附加到更大的缓冲区。

读取N个字节,直到读取返回0

是!

一个补充细节。 如果发件人没有关闭连接,套接字将只是阻塞,而不是返回。 当没有任何内容可读时,非阻塞套接字将返回-1(使用errno == EAGAIN ); 那是另一种情况。

以二进制模式打开文件并获取大小将有助于我知道给缓冲区的正确大小?

不。 套接字没有大小。 假设您通过同一连接发送了两条消息:文件有多长?