我正在用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] = '\0';
if (fputs(buffer, stdout) == EOF)
error("fputs");
}
if (n < 0)
error("reading from socket");
printf("out of the loop\n");
我无法理解的是为什么程序永远不会进入最后的printf
调用,而是坐在那里,就像从服务器等待更多。这是否意味着最后一个回复长于0并且IRC服务器在发送另一个命令之前不会发送任何新内容?
如果是这样(冒着离开这里的话题),并且read()
正在阻塞,那么在程序等待该调用返回时,我会在哪里编写向服务器发送命令的逻辑?
我无法理解的是为什么程序永远不会进入最后的printf调用,而是坐在那里,好像等待来自服务器的更多。
它正在等待来自服务器的更多内容。当对等体断开连接时,qazxsw poi将返回零,而不是之前。
尽管你的程序不完整,但你有一些错误的假设。我们在您的代码中对这些进行评论。
read()
while ((n = read(sockfd, buffer, sizeof(buffer)-1)) > 0) {
字节来完成它,那么阅读sizeof(buffer)-1
会很好,但是想想你可以从套接字接收\0
,如果你想成为一般的,不要以为你总是在阅读文本。许多安全漏洞都来自这样的错误。程序员(错误地)假定数据是ascii文本,并且有人利用缓冲区溢出(不是这种情况)或非法的东西,提供大量空字符以使其失败。
\0
printf("\nloop\n");
buffer[n] = '\0';
if (fputs(buffer, stdout) == EOF)
放在缓冲区的末尾时,stdio会在看到它之后立即将所有内容打印到最后一个缓冲区。好吧,为了实现这一点,\n
检查描述符是否与终端相关联(通过stdio
调用,或调用ioctl(2)
)。对于套接字不再适用,因此可能已将缓冲区复制到stdio缓冲区,并且stdio正在等待缓冲区填充,或者在调用isatty(3)
以通过它发送所有数据之前使用fflush(3)
显式刷新缓冲区。
write(2)
error("fputs");
,所以你确定你的所有数据都被发送到同行,然后继续,或者根本不使用stdio(使用简单的fflush(stdout);
调用,直到你足够精通准备一个write(2)
s的线程套接字一旦准备好接受更多数据就可以提供更多数据)
select(2)