从套接字读取

时间:2010-06-16 13:41:19

标签: c sockets

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

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

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

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

5 个答案:

答案 0 :(得分:17)

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

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

  

我认为最好的方法是阅读N.   字节,直到读取返回0(否   插槽中的更多作者)。这是   正确?

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

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

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

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

  

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

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

  

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

是!

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

  

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

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