用fcntl设定socket为非阻塞
Posted 邱洋inCloud
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用fcntl设定socket为非阻塞相关的知识,希望对你有一定的参考价值。
第一部分
-------------------------------------------------------------------------------------------------------------------
How would I put my socket in non-blocking mode?
From Andrew Gierth (andrew@erlenstar.demon.co.uk):
Technically, fcntl(soc, F_SETFL, O_NONBLOCK) is incorrect since it clobbers all other file flags. Generally one gets away with it since the other flags (O_APPEND for example) don't really apply much to sockets. In a similarly rough vein, you would use fcntl(soc, F_SETFL, 0) to go back to blocking mode.
To do it right, use F_GETFL to get the current flags, set or clear the O_NONBLOCK flag, then use F_SETFL to set the flags.
And yes, the flag can be changed either way at will.
From: jagadeesh
Code:
/* set socket to non-blocking i/o */
sts = ioctl(ccp->main_sock, FIONBIO, (char *)&one);
if (sts)
{
setproderr(PE_TCPERROR, GEL_FATAL);
sprintf(line,"ioctl (main) failed - %s",strerror(errno));
tcpabort();
}
From: Viswaroopan
Hi,
I tried this and works great as non-blocking socket. I have a different problem is that, when I made it as non-blocking the accept() on the server comes out immediately with non-block error. Instead I want accept() to wait for some time (set a timeout) before giving that error. Is there any way I can set the timeout on accept().
Thanks in advance.
Vish
From: Jonathan Rynd
This is normal for all socket nonblocking operations: if you call them, you should be prepared to handle 2 cases: 1, they succeed right away, 2, they 'fail' with the "EWOULDBLOCK" non-blocking error (it's not a real failure, it just means "we can't satisfy that right now'. You then have to create a FD_SET structure and use it as input to select() with the proper timeout. See the manpage for select. Depending on the call, when select() returns to indicate success, you may need to make the call again.
From:
sorry, but a little more source code would help me more cause i do know nothing about ioctl and need a nonblocking socket...
cause i want to have a read, that doesent stop the whole program
and, what about this stuff with select()
how do i get a buffer that stores a recived package and give it to me when i ask, if there is a new one, or says no, there is no new package, if there is none
From: jesus
aehrm forgot my email...
sorry, but a little more source code would help me more cause i do know nothing about ioctl and need a nonblocking socket...
cause i want to have a read, that doesent stop the whole program
and, what about this stuff with select()
how do i get a buffer that stores a recived package and give it to me when i ask, if there is a new one, or says no, there is no new package, if there is none
From: Michael Lampkin
Added on: 2002-06-01 00:53:57
Since this is a common question... the follow is sample code showing setting and un-setting for non-blocking on a socket.
Code:
int flags;
/* Set socket to non-blocking */
if ((flags = fcntl(sock_descriptor, F_GETFL, 0)) < 0)
{
/* Handle error */
}
if (fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK) < 0)
{
/* Handle error */
}
/* Set socket to blocking */
if ((flags = fcntl(sock_descriptor, F_GETFL, 0)) < 0)
{
/* Handle error */
}
if (fcntl(socket_descriptor, F_SETFL, flags & (~O_NONBLOCK)) < 0)
{
/* Handle error */
}
第二部分
-------------------------------------------------------------------------------------------------------
1)connect超时:
1)setsockopt();//将socket置为非阻塞模式;
2)connect();
3)判断connect()的返回值,一般情况会返回-1,这时你还必须判断错误码如果是EINPROGRESS,那说明connect还在继续;如果错误码不是前者那么就是有问题了,不必往下执行,必须关掉socket;待下次重联;
4)select();设置好函数中的超时时间,将select()中的read和write项置上,在超时时间内,如果select返回1,即描述字变为了可写,那么连接成功;如果返回2,即描述字变为即可读又可写,那么出错;如果返回0,那么超时;
============================================
2.网络中断:
如果你的程序是客户端.用select检查描述符的状态,如果可读就recv(),根据recv()的返回值来判断网络情况;
/********************************************/
/**** 作者::夕君 **/
/**** 时间:2004.04.04 **/
/**** 北京金万维科技 http://www.gnway.com **/
/*******************************************/
/*此函数实现判断m_server的m_port端口是否可以连上,超时限制为nTimeOut秒*/
BOOL ConnectTest(char * m_server,int m_port)
{
struct hostent* host = NULL;
struct sockaddr_in saddr;
unsigned int s = 0;
BOOL ret;
time_t start;
int error;
host = gethostbyname (m_server);
if (host==NULL)return FALSE;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(m_port);
saddr.sin_addr = *((struct in_addr*)host->h_addr);
if( (s=socket(AF_INET, SOCK_STREAM, 0))<0){
return FALSE;
}
fcntl(s,F_SETFL, O_NONBLOCK);
if(connect(s,(struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
if (errno == EINPROGRESS){// it is in the connect process
struct timeval tv;
fd_set writefds;
tv.tv_sec = m_nTimeOut;
tv.tv_usec = 0;
FD_ZERO(&writefds);
FD_SET(s, &writefds);
if(select(s+1,NULL,&writefds,NULL,&tv)>0){
int len=sizeof(int);
//下面的一句一定要,主要针对防火墙
getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len);
if(error==0) ret=TRUE;
else ret=FALSE;
}else ret=FALSE;//timeout or error happen
}else ret=FALSE;
}
else ret=TRUE;
close(s);
return ret;
}
以上是关于用fcntl设定socket为非阻塞的主要内容,如果未能解决你的问题,请参考以下文章