2010-06-16 98 views
8

我需要使用C函数read从AF_UNIX插槽读取缓冲区,但我不知道缓冲区大小。从插座读取

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

我在想套接字是一个特殊的文件。以二进制模式打开文件并获取大小会帮助我了解缓冲区的正确大小?

我是一个非常新的C,所以请记住这一点。

回答

14

通常的方法是使用ioctl(..)查询套接字的FIONREAD,该套接字将返回有多少数据可用。

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

嗨,谢谢。 阅读中的第四个参数是什么? – Donovan 2010-06-17 10:52:21

+1

@Alberto,啊,这是一个错字。应该只有3读,我先写了'recv'... – epatel 2010-06-17 16:37:04

0

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

0

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

是的!

一个增加的细节。如果发送者没有关闭连接,套接字将会被阻塞,而不是返回。当没有东西可读时,非阻塞套接字将返回-1(与errno == EAGAIN);那是另一种情况。

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

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

1

我认为最好的办法是读取N个字节 直到读取(在插座没有 更多作家)返回0。这是 是否正确?

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

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

操作系统已经为您分配了数据报套接字。如果需要的话,必须在应用程序级别上实现:例如,通过在消息头结构中定义一个大小字段或使用分隔符(例如' \ n'用于单行文本消息)。在第一种情况下,您首先要读取标题,提取长度并使用长度读取消息的其余部分。在其他情况下,将流读入部分缓冲区,搜索分隔符并从缓冲区中提取包含分隔符的消息(您可能需要保留部分缓冲区,具体取决于协议)可以使用单个recv()/ read() ))。

有没有办法猜测 的缓冲区大小是否写在 的socket?

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

对于数据报套接字,通常事先知道消息的大小。或者可以尝试(从来没有做过)recvmsg(MSG_PEEK),如果MSG_TRUNC在返回的msghdr.msg_flags中,则尝试增加缓冲区大小。

2

从套接字读取未知数量的同时避免阻塞的一种方法可能是poll()一个非阻塞套接字的数据。

E.g.

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);