阻塞和非阻塞的一点使用心得

在《unp》书上,stevent一开始的一个服务器小例子这样介绍到:一个TCP的服务器和客户

端,客户端puts进行阻塞式的输入消息。暴露的问题是,当用户进行阻塞到puts输入时,对方

的服务器关闭,那么用户可能发了一大断消息按下发送时,发现程序崩溃了。。阻塞的出现的

另一种意义就是各司职。 最近在负责的一个项目中,需要频繁的进行TCP吞吐,我一时认为不


需要什么阻塞,都是即时的消息,而且又很频繁。结果暴露的问题出来了:(9060为服务端)
1、如
tcp        0  16385 218.66.25.238:32821     218.66.25.238:9060      FIN_WAIT1 
tcp 60416 0 218.66.25.238:9060 218.66.25.238:32821 ESTABLISHED

tcp 0 36 218.66.25.238:22 218.66.25.222:1874 ESTABLISHED
tcp 0 0 218.66.25.238:32821 218.66.25.238:9060 TIME_WAIT


哦是的,我卡住了。我在发送数据的时候阻塞了。而且当我我把客户端关闭时,发送第一个

TCP FIN后,客户端状态为FIN_WAIT1,这时我期待着对方的返回。(TCP SYS 和 socket fin)

可是,看到60416了吗,服务器的缓冲区满了。我不得不等到服务套接字将他们都取完后才结

束。但是这个阻塞影响了我一些线程方面的判断。或许你会说, 谁叫你把recv和send设置得

不一样。这个我承认,但是你也得考虑到,万一网速不那么顺畅,可能会造成一方发送较快,

导致在缓冲区里累计一些包,长久以后,程序必然崩溃;当然还包括当你机器繁忙时,recv和

send执行得也许不那么顺利呢?这些都是隐患。

所以考虑下,决定用select执行。代码如下:

int CCreateTCP_UDP::Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = (const char*)vptr;
nleft = n;
while (nleft > 0)
{
if ( (nwritten = write(fd, ptr, nleft)) <= 0)
{
if (errno == EINTR)
nwritten = 0; /* and call write() again

*/
else
return(-1); /* error */
}

nleft -= nwritten;
ptr += nwritten;
}
return(n);
}

int CCreateTCP_UDP::WritenUBlock(int fd, const void *vptr, size_t n)
{
fd_set set_write;
timeval time_out;

FD_ZERO(&set_write);
FD_SET(fd, &set_write);
time_out.tv_sec=time_out.tv_usec=3; //可能会被改变
if( select(fd+1, NULL, &set_write, NULL, &time_out)==-1 )
{
return -1;
}
/*select可能返回>0的数,为了防止0套接字,进行个判断
所以这里要注意保持收和发的平衡性
尽量减少缓冲区的饱和
*/
if( FD_ISSET(fd, &set_write) )
{
/*为了防止数据上的一些连包,返回错误重新处理*/
if( Writen( fd, vptr, n )!=n)
{
return -1;
}
}
/*成功的话,理所当然返回发送的字节数,不过既然能通过!=n,
就简单的以统一的0表示成功*/
return 0;
}


一些代码是照抄《unp》上的。

这里做点解释:在WritenUBlock这个函数里,首先将套接字放入FD_SET的类型,接着用select

查询。用select我们当然希望它当套接字可以用时告诉我们。

可以有如下几个情况(总结的不是很完全)

1 当缓冲区中的数据满足读的条件(比如你的套接字至少要10个字节,而这时候缓冲区中的数

据长度满足)

2 当socket发生错误时。这里大家可能不明白,为什么要socket发生错误时。很好理解,当我

们用一个套接字时,最希望的是当它可以用的时候告诉我们,起码使用它时不会崩溃。既然这

样的话,发生错误是不是也在我们范围之内呢?

错误有两种,
一是1;这表示发生了一个调用错误,要和普通的数据接收错误分开,这是一个函数的调用错误

二是0;很不幸,这表示它读到了一个EOF字符。表示对方要跟你断开了,这里细节如下:当对

方进程结束或者调用close,对方的TCP首先发送一个FIN,我方回复这个FIN,接着我方的TCP向

这个套接字的缓冲区送一个EOF,等带着套接字调用,当我方套接字收到这个0,就发送一个

socket的FIN,对方接着回复这个FIN。一环扣着一环,具体见我上一篇BLOG,《time_wait状

态的解释和验证》。

这就是今天我对阻塞和非阻塞的一点认识,当然对select的工作系统还不熟悉,只是初步的使

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值