Linux服务器

时间:2022-01-21 05:20:42
/*** cloud_sum_server ***/
void cloud_sum(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
long a = , b = ;
again:
while ( (n = read(sockfd, buf, MAXLINE)) > ){
if (sscanf(buf, "%ld %ld", &a, &b) > )
snprintf(buf, sizeof(buf), "%ld\n", a + b);
else
snprintf(buf, sizeof(buf), "input error\n"); n = strlen(buf);
write(sockfd, buf, n);
fputs(buf, stdout);
bzero(buf, sizeof(char) * MAXLINE);
} if (n < && EINTR == errno)
goto again;
else if (n < )
cout<<"read error!"<<endl;
else if ( == n)
cout<<"EOF"<<endl;
}

单进程和使用select的服务器程序

第一个客户建立连接前的服务器状态:

Linux服务器

服务器只维护一个读描述符集时:描述符0、1和2分别被设置为标准输入、标准输出和标准错误输出,故监听套接字的第一个可用描述符是3。

描述符集中唯一的非0项是表示监听套接字的项,因此select的第一个参数将为4。

Linux服务器    Linux服务器

client整型数组包含了每个客户的已连接套接字描述符,所有元素初始化为-1。

当第一个客户与服务器建立连接时,监听描述符变为可读,服务器于是调用accept。本例中accept返回的新的已连接描述符将是4。

Linux服务器

从现在起,服务器必须在client数组中记住每个新的已连接描述符,并将它们加到描述符集中去。

Linux服务器    Linux服务器

第二个客户与服务器建立连接:

Linux服务器

Linux服务器    Linux服务器

如果第一个客户终止它的连接,该客户的TCP发送一个FIN,使得服务器中的描述符4变为可读。

当服务器读这个已连接套接字时,read将返回0,于是关闭该套接字并相应地更新数据结构:

把client[0]的值置为-1,把描述符4的位设置为0,但maxfd的值不变。

Linux服务器    Linux服务器

当有新客户到达时,在client数组的第一个可用项(即值为-1的第一个项)中记录其已连接套接字的描述符,并把它加到读描述符集中。

服务器所能处理的最大客户数目的限制是以下两个值中的较小值:FD_SETSIZE和内核允许本进程打开的最大描述符数。

如果一个恶意客户连接到服务器,发送一个字节的数据(不是换行)后进入睡眠。

服务器将调用read从客户读入这个单字节的数据,然后阻塞于下一个read调用,以等待来自该客户的其余数据。

服务器于是因为这个客户而被阻塞(挂起),不能为其他任何客户提供服务,直到那个恶意客户发出一个换行符或终止为止。(拒绝服务denial of service攻击)。

可解决的办法如:

1)使用非阻塞式I/O;

2)让每个客户由单独的控制线程提供服务(例如创建一个子进程或一个线程来服务每个客户);

3)对I/O操作设置一个超时。