Unix网络编程说明 [英] Unix Network Programming Clarification
问题描述
我正在阅读经典书籍 Unix网络编程,当我偶然发现此程序时(第6.8节,第179-180页)
I was going through the classic book Unix Network Programming, when I stumbled upon this program (Section 6.8, page 179-180)
#include "unp.h"
int
main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for ( ; ; ) {
rset = allset; /* structure assignment */
nready = Select(maxfd+1, &rset, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &rset)) { /* new client connection */
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready <= 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
/*4connection closed by client */
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
} else
Writen(sockfd, buf, n);
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
}
作者提到此程序对DOS攻击并不安全。从书中引用
The author mentions that this program is not safe against DOS attack. Quoting from the book,
不幸的是,我们刚刚展示的服务器存在问题。请考虑一下,如果恶意客户端连接到服务器,会发生什么情况,发送一个字节的数据(而不是换行符),然后进入睡眠状态,服务器将调用 read (系统调用),系统将从客户端读取单个数据字节,然后进行阻止在下一次调用 read 的过程中,等待来自此客户端的更多数据。然后,该服务器被该客户端阻止,除非恶意客户端发送换行符或终止,否则该服务器将不再为其他客户端提供服务。 / em>
"Unfortunately, there is a problem with the server that we just showed. Consider what happens if a malicious client connects to the server, sends one byte of data (other than a newline), and then goes to sleep. The server will call read (system call), which will read the the single byte of data from the client and then block in the next call to read, waiting for more data from this client. The server is then blocked by this one client, and will not service any other clients until malicious client either sends a newline or terminates"
我不确定我是否理解正确。为什么第二次调用此恶意客户端的 read 系统调用,因为它仅发送了1字节的数据,而第一次调用 select 会通知该数据。后续对 select 的调用将永远不会设置此恶意文件描述符,因为没有活动。我在这里遗漏了什么吗?
I am not sure if I understand this correctly. Why will the read system call be called the second time for this malicious client, since it only sent 1 byte of data, that gets notified by the first call to select. The subsequent calls to select will never have this malicious file descriptor set as there is no activity. Am I missing something here?
我的猜测是代码中有错别字,而不是Read,应该是其他地方提到的Readline方法的某个版本在书里。
My guess here is that there is a typo in the code, instead of Read, it should be some version of Readline method mentioned at other places in the book.
注意:该代码包含 Read 和 Select (大写的R和S ),它们不过是由 read 和 select 系统调用
Note: The code contains Read and Select (with capital R and S), which are nothing but error handled wrappers of read and select system call
推荐答案
是的,似乎原本打算是 Readline
。
Yes, it seems likely that it was intended to be Readline
.
在可下载的源代码该文件为 tcpcliserv / tcpservselect01.c
并且有一个相应的 .lc
文件(带有行号注释),该文件使用 Readline
而不是阅读
,在本书第二版中是 Readline
(源代码)。理解括号注释(除了换行符)的唯一方法是假设预期的读取函数可以读取换行符。
In the downloadable source code that file is tcpcliserv/tcpservselect01.c
and there is a corresponding .lc
file (with line number annotations) which uses Readline
instead of Read
, and it was Readline
in the second edition of the book (source code). About the only way to make sense of the parenthetic comment "(other than a newline)" is to assume that the intended read function reads up to a newline.
Oddly, it hasn't been reported in the errata. Maybe you should do so.
这篇关于Unix网络编程说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!