C语言 从套接字读取

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3053757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:40:36  来源:igfitidea点击:

Read from socket

csockets

提问by Donovan

I need to read from an AF_UNIX socket to a buffer using the function readfrom C, but I don't know the buffer size.

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

I think the best way is to read Nbytes until the read returns 0(no more writers in the socket). Is this correct? Is there a way to guess the size of the buffer being written on the socket?

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

I was thinking that a socket is a special file. Opening the file in binary mode and getting the size would help me in knowing the correct size to give to the buffer?

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

I'm a very new to C, so please keep that in mind.

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

回答by epatel

On common way is to use ioctl(..)to query FIONREADof the socket which will return how much data is available.

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

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

回答by Maister

One way to read an unknown amount from the socket while avoiding blocking could be to poll() a non-blocking socket for data.

在避免阻塞的同时从套接字读取未知数量的一种方法可能是 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); 

回答by yurib

you are correct, if you don't know the size of the input you can just read one byte each time and append it to a larger buffer.

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

回答by Dummy00001

I think the best way is to read N bytes until the read returns 0 (no more writers in the socket). Is this correct?

我认为最好的方法是读取 N 个字节,直到读取返回 0(套接字中不再有写入者)。这样对吗?

0 means EOF, other side has closed the connection. If other side of communication closes the connection, then it is correct.

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

If connection isn't closed (multiple transfers over the same connect, chatty protocol), then the case is bit more complicated and behavior generally depends on whether you have SOCK_STREAM or SOCK_DGRAM socket.

如果连接未关闭(通过同一个连接、闲聊协议进行多次传输),则情况会复杂一些,行为通常取决于您是否有 SOCK_STREAM 或 SOCK_DGRAM 套接字。

Datagram sockets are already delimited for you by the OS.

数据报套接字已经由操作系统为您定界。

Stream sockets do not delimit messages (all data are an opaque byte stream) and if desired one has to implement that on application level: for example by defining a size field in the message header structure or using a delimiter (e.g. '\n' for single-line text messages). In first case you would first read the header, extract length and using the length read the rest of the message. In other case, read stream into partial buffer, search for the delimiter and extract from buffer the message including the delimiter (you might need to keep the partial buffer around as depending on protocol several command can be received with single recv()/read()).

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

Is there a way to guess the size of the buffer being written on the socket?

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

For stream sockets, there is no reliable way as the other side of communication might be still in process of writing the data. Imagine the quite normal case: socket buffer is 32K and 128K is being written. Writing application would block inside send()/write(), the OS waiting for reading application to read out the data and thus free space for the next chunk of written data.

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

For datagram sockets, one normally knows the size of the message beforehand. Or one can try (never did that myself) recvmsg( MSG_PEEK ) and if the MSG_TRUNC is in the returned msghdr.msg_flags, try to increase the buffer size.

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

回答by Andres Jaan Tack

read N bytes until the read returns 0

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

Yes!

是的!

One added detail. If the sender doesn't close the connection, the socket will just block, instead of returning. A nonblocking socket will return -1 (with errno == EAGAIN) when there's nothing to read; that's another case.

一个补充细节。如果发送方没有关闭连接,套接字将阻塞,而不是返回。非阻塞套接字将errno == EAGAIN在没有可读取的内容时返回 -1(带有);那是另一种情况。

Opening the file in binary mode and getting the size would help me in knowing the correct size to give to the buffer?

以二进制模式打开文件并获取大小将帮助我了解提供给缓冲区的正确大小?

Nope. Sockets don't have a size. Suppose you sent two messages over the same connection: How long is the file?

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