最近写的程序要求的是在控制线程中使用非阻塞的socket,以前没怎么接触过,先贴出代码如下:
#define sockopt_noblock(socket, noblock) do{\
int val = (noblock);\
ioctl((socket), FIONBIO, (int)&val);\
} while(0)
int conn_nonb(int sockfd, const struct sockaddr_in *saptr, socklen_t salen, int nsec)
{
int flags, n, error, code;
socklen_t len;
fd_set wset;
struct timeval tval;
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
sockopt_noblock(sockfd, 1);
error = 0;
if ((n == connect(sockfd, (struct sockaddr *)saptr, salen)) == 0) {
goto done;
} else if (n < 0 && errno != EINPROGRESS){
return RS_ERROR;
}
/* Do whatever we want while the connect is taking place */
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
tval.tv_sec = nsec;
tval.tv_usec = 0;
if ((n = select(sockfd+1, NULL, &wset,
NULL, nsec ? &tval : NULL)) == 0) {
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return RS_ERROR1;
}
if (FD_ISSET(sockfd, &wset)) {
len = sizeof(error);
code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
/* 如果发生错误,Solaris实现的getsockopt返回-1,
* 把pending error设置给errno. Berkeley实现的
* getsockopt返回0, pending error返回给error.
* 我们需要处理这两种情况 */
if (code < 0 || error) {
close(sockfd);
if (error)
errno = error;
return RS_ERROR;
}
} else {
fprintf(stderr, "select error: sockfd not set");
exit(0);
}
done:
//fcntl(sockfd, F_SETFL, flags); /* restore file status flags ,这里看你自身的情况,可以选择恢复或者不恢复 */
return RS_OK; /* return 0 */
}
注:此代码是别人写的,可以拿来直接用,但是在这里连接只能保证你connect的时候是成功的,但是不能保证你后续read、write、send、recv是成功的。因此你需要在每次
read和write前检查连接是否断开。可以通过以下办法来判断(也是网上查找的资料,自己用过,是这样的):
在阻塞模式下,
recv和read 一般返回0,断开。(这个待议,我没试过)
非阻塞模式下,
错误代码是EAGAIN/EWOULDBLOCK时,表示正常,未读写数据。
recv()或read()返回0时,表示断开,返回-1而errno不是EAGAIN/EWOULDBLOCK时,表示有其他错误,一般建议断开。
这里有其他的判断方法,其实和我上面说的一致。
正常断开连接情况下,判断非阻塞模式socket连接是否断开
摘自:http://blog.chinaunix.net/uid-15014334-id-3429627.html
在UNIX/LINUX下,
1,对于主动关闭的SOCKET, recv返回-1,而且errno被置为9(#define EBADF 9 /* Bad file number */)或104 (#define ECONNRESET 104 /* Connection reset by peer */)
2,对于被动关闭的SOCKET,recv返回0,而且errno被置为11(#define EWOULDBLOCK EAGAIN /* Operation would block */)
3,对正常的SOCKET, 如果有接收数据,则返回>0, 否则返回-1,而且errno被置为11(#define EWOULDBLOCK EAGAIN /* Operation would block */)
因此对于简单的状态判断(不过多考虑异常情况),
recv返回>0, 正常
返回-1,而且errno被置为11 正常
其它情况 关闭