从套接字读取时如何处理阻塞的 read() 调用?
How to handle blocking read() call when reading from a socket?
出于自学目的,我正在用 C 语言编写一个简单的 IRC 客户端程序,但在调用从套接字文件描述符读取时无法理解 read()
函数的行为。
以下代码片段有效并打印与 运行
相同的输出
$ echo "NICK gertrudes\r\nUSER a 0 * d\r\n" | nc chat.freenode.net 6667
在终端中,这与我的程序到目前为止打印的相同:
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
printf("\nloop\n");
buffer[n] = '[=10=]';
if (fputs(buffer, stdout) == EOF)
error("fputs");
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");
我不明白的是为什么程序永远不会到达最后的 printf
调用,而是坐在那里,好像在等待来自服务器的更多信息。这是否意味着最后的回复比 0 长并且 IRC 服务器在我发送另一个命令之前不会发送任何新内容?
如果是这样(这里有跑题的风险),并且 read()
正在阻塞,那么在程序等待对 return?
What I fail to understand is why the program never gets to the final printf call, and rather sits there as if waiting for more from the server.
它正在等待来自服务器的更多信息。 read()
将 return 在对等方断开连接时归零,之前不会。
尽管您的程序不完整,但您错误地假设了几件事。让我们在您的代码中注释这些内容。
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
如果你打算用[=15=]
一个字节来完成它,读sizeof(buffer)-1
很好,但认为你可以接收 a [=15=]
来自套接字,如果你想笼统,不要假设你总是在阅读文本。许多安全漏洞都来自这样的错误。程序员(错误地)假设数据是 ascii 文本,有人利用缓冲区溢出(事实并非如此)或一些非法的东西,提供大量空字符使其失败。
printf("\nloop\n");
buffer[n] = '[=11=]';
if (fputs(buffer, stdout) == EOF)
这是一个非常常见的错误...当你在缓冲区的末尾放置一个 \n
时,你习惯看到, stdio 会在看到最后一个缓冲区之前立即打印所有内容。好吧,为了实现这一点,stdio
检查描述符是否与终端相关联(通过 ioctl(2)
调用或对 isatty(3)
的调用)。对于套接字不再如此,因此可能您的缓冲区已被复制到 stdio 缓冲区,并且 stdio 正在等待缓冲区填充,或者您在调用 write(2)
发送之前用 fflush(3)
显式刷新缓冲区上面的所有数据。
error("fputs");
在这一点上做一个fflush(stdout);
,这样你就可以确定你所有的数据都被发送到对端,然后再继续,或者根本不使用stdio(使用简单的write(2)
调用,直到您足够熟练地准备一个 select(2)
套接字上的线程,以便在它准备好接受更多数据时立即提供更多数据)
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");
出于自学目的,我正在用 C 语言编写一个简单的 IRC 客户端程序,但在调用从套接字文件描述符读取时无法理解 read()
函数的行为。
以下代码片段有效并打印与 运行
相同的输出$ echo "NICK gertrudes\r\nUSER a 0 * d\r\n" | nc chat.freenode.net 6667
在终端中,这与我的程序到目前为止打印的相同:
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
printf("\nloop\n");
buffer[n] = '[=10=]';
if (fputs(buffer, stdout) == EOF)
error("fputs");
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");
我不明白的是为什么程序永远不会到达最后的 printf
调用,而是坐在那里,好像在等待来自服务器的更多信息。这是否意味着最后的回复比 0 长并且 IRC 服务器在我发送另一个命令之前不会发送任何新内容?
如果是这样(这里有跑题的风险),并且 read()
正在阻塞,那么在程序等待对 return?
What I fail to understand is why the program never gets to the final printf call, and rather sits there as if waiting for more from the server.
它正在等待来自服务器的更多信息。 read()
将 return 在对等方断开连接时归零,之前不会。
尽管您的程序不完整,但您错误地假设了几件事。让我们在您的代码中注释这些内容。
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
如果你打算用
[=15=]
一个字节来完成它,读sizeof(buffer)-1
很好,但认为你可以接收 a[=15=]
来自套接字,如果你想笼统,不要假设你总是在阅读文本。许多安全漏洞都来自这样的错误。程序员(错误地)假设数据是 ascii 文本,有人利用缓冲区溢出(事实并非如此)或一些非法的东西,提供大量空字符使其失败。printf("\nloop\n"); buffer[n] = '[=11=]'; if (fputs(buffer, stdout) == EOF)
这是一个非常常见的错误...当你在缓冲区的末尾放置一个
\n
时,你习惯看到, stdio 会在看到最后一个缓冲区之前立即打印所有内容。好吧,为了实现这一点,stdio
检查描述符是否与终端相关联(通过ioctl(2)
调用或对isatty(3)
的调用)。对于套接字不再如此,因此可能您的缓冲区已被复制到 stdio 缓冲区,并且 stdio 正在等待缓冲区填充,或者您在调用write(2)
发送之前用fflush(3)
显式刷新缓冲区上面的所有数据。error("fputs");
在这一点上做一个
fflush(stdout);
,这样你就可以确定你所有的数据都被发送到对端,然后再继续,或者根本不使用stdio(使用简单的write(2)
调用,直到您足够熟练地准备一个select(2)
套接字上的线程,以便在它准备好接受更多数据时立即提供更多数据)} if (n < 0) error("reading from socket"); printf("out of the loop\n");