将阻塞模式的socket连结变为非阻塞模式
2009-09-28 15:49
459 查看
发信人: landyhorse (马儿), 信区: NetPRG
标 题: ---将阻塞模式的socket连结变为非阻塞模式---
发信站: BBS 水木清华站 (Fri Dec 7 15:45:40 2001)
前两天在linux下作了这方面的应用,
当时也是找了好半天才搞出来,
看到有人问,就讲讲基本原理,和一段代码,免得大家再走弯路
该方法最适合线程使用
1。原理(来自linuxforum)
创建socket后,先把connect()用的socket的模式保存,
再将其设成nonblock模式(使用fcntl函数),
然后进行connect()。
connect()会return两种情况,一是success,
那就restore socket的以前mode, again use fcntl(), 然后
就算connect好了,二则是-1, 那么就要看errno, 如果是
EINPROGRESS,则就用把socket加到FD_SET里,然后用select()
select socket for writting.
因为select()可以用timeout, 然后如果select() return的话,
如果return 0, 那就是timeout, -1就要看你根据errno如何处理了,
如果是>0, 则用FD_ISSET()看是否是socket connect好了,这时
还有个condition是connection refused, 对方送了你一个RST,
你需要用getsockopt(sockfd, SOL_SOCKET,SO_ERROR,....)去
查一下,如果没有问题那就是connect success了
2.例程代码(来自白云黄鹤)
/************************************************************************
* tcpconnect.c, by digger, 带超时限制的非阻塞式connect *
************************************************************************/
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <fcntl.h>
# include <unistd.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <errno.h>
/************************************************************************
* 函数: tcpconnect( ) *
* 输入: char * server_addr, u_short server_port, int limit_seconds *
* 成功: 返回创建并连接服务端成功的socket文件号, 失败: 返回-1 *
************************************************************************/
int tcpconnect( char * server_addr, /* 服务端地址, 域名或IP地址 */
u_short server_port, /* 服务端口 */
int limit_seconds /* 超时限制, 单位为秒 */
)
{
struct hostent * hp; /* host entry pointer */
struct sockaddr_in server; /* server address structure */
int sock; /* socket to create */
fd_set fdW; /* fileds to be select */
struct timeval timeout; /* timeout parameter */
int fflag; /* file flag for fcntl */
int errcode; /* error code for getsockopt */
int errlen; /* length of errcode */
/* fill in server address structure with ip address and port */
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
if ((hp = gethostbyname(server_addr)) == NULL) {
if ((server.sin_addr.s_addr = inet_addr(server_addr)) == -1) {
fprintf(stderr, "%s: unknown host/n", server_addr);
exit(1);
}
} else {
bcopy(hp->h_addr_list[0], &server.sin_addr, hp->h_length);
}
/* create client socket and connect it to server */
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
return(-1);
}
/* get original sock flag */
if ((fflag = fcntl(sock, F_GETFL, 0)) < 0) {
perror("fcntl get file flag");
exit(-1);
}
/* set O_NDELAY flag to sock */
if (fcntl(sock, F_SETFL, fflag|O_NDELAY) < 0) {
perror("fcntl set file flag O_NDELAY");
exit(-1);
}
/* connect to server using nonblock mode */
connect(sock, (struct sockaddr *)&server, sizeof(server));
/* set timeout structure */
timeout.tv_sec = limit_seconds;
timeout.tv_usec = 0;
FD_ZERO(&fdW);
FD_SET(sock, &fdW);
CNNT_AGAIN:
switch(select(sock + 1, NULL, &fdW, NULL, &timeout)) {
case -1:
if (errno == EINTR) goto CNNT_AGAIN; /* call interrupted */
close(sock); /* select error */
exit(-1);
case 0:
close(sock);
return(-1);
default:
if (FD_ISSET(sock, &fdW)) { /* check if socket writable */
errlen = sizeof(errcode);
getsockopt(sock, SOL_SOCKET, SO_ERROR,
(char *)&errcode,&errlen);
if(errcode == 0) { /* check if connect right */
/* reset original sock flag */
if (fcntl(sock, F_SETFL, fflag) < 0) {
perror("fcntl reset file flag");
exit(-1);
}
return(sock);
} else {
close(sock);
return(-1);
}
}
}
标 题: ---将阻塞模式的socket连结变为非阻塞模式---
发信站: BBS 水木清华站 (Fri Dec 7 15:45:40 2001)
前两天在linux下作了这方面的应用,
当时也是找了好半天才搞出来,
看到有人问,就讲讲基本原理,和一段代码,免得大家再走弯路
该方法最适合线程使用
1。原理(来自linuxforum)
创建socket后,先把connect()用的socket的模式保存,
再将其设成nonblock模式(使用fcntl函数),
然后进行connect()。
connect()会return两种情况,一是success,
那就restore socket的以前mode, again use fcntl(), 然后
就算connect好了,二则是-1, 那么就要看errno, 如果是
EINPROGRESS,则就用把socket加到FD_SET里,然后用select()
select socket for writting.
因为select()可以用timeout, 然后如果select() return的话,
如果return 0, 那就是timeout, -1就要看你根据errno如何处理了,
如果是>0, 则用FD_ISSET()看是否是socket connect好了,这时
还有个condition是connection refused, 对方送了你一个RST,
你需要用getsockopt(sockfd, SOL_SOCKET,SO_ERROR,....)去
查一下,如果没有问题那就是connect success了
2.例程代码(来自白云黄鹤)
/************************************************************************
* tcpconnect.c, by digger, 带超时限制的非阻塞式connect *
************************************************************************/
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <fcntl.h>
# include <unistd.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <errno.h>
/************************************************************************
* 函数: tcpconnect( ) *
* 输入: char * server_addr, u_short server_port, int limit_seconds *
* 成功: 返回创建并连接服务端成功的socket文件号, 失败: 返回-1 *
************************************************************************/
int tcpconnect( char * server_addr, /* 服务端地址, 域名或IP地址 */
u_short server_port, /* 服务端口 */
int limit_seconds /* 超时限制, 单位为秒 */
)
{
struct hostent * hp; /* host entry pointer */
struct sockaddr_in server; /* server address structure */
int sock; /* socket to create */
fd_set fdW; /* fileds to be select */
struct timeval timeout; /* timeout parameter */
int fflag; /* file flag for fcntl */
int errcode; /* error code for getsockopt */
int errlen; /* length of errcode */
/* fill in server address structure with ip address and port */
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
if ((hp = gethostbyname(server_addr)) == NULL) {
if ((server.sin_addr.s_addr = inet_addr(server_addr)) == -1) {
fprintf(stderr, "%s: unknown host/n", server_addr);
exit(1);
}
} else {
bcopy(hp->h_addr_list[0], &server.sin_addr, hp->h_length);
}
/* create client socket and connect it to server */
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket");
return(-1);
}
/* get original sock flag */
if ((fflag = fcntl(sock, F_GETFL, 0)) < 0) {
perror("fcntl get file flag");
exit(-1);
}
/* set O_NDELAY flag to sock */
if (fcntl(sock, F_SETFL, fflag|O_NDELAY) < 0) {
perror("fcntl set file flag O_NDELAY");
exit(-1);
}
/* connect to server using nonblock mode */
connect(sock, (struct sockaddr *)&server, sizeof(server));
/* set timeout structure */
timeout.tv_sec = limit_seconds;
timeout.tv_usec = 0;
FD_ZERO(&fdW);
FD_SET(sock, &fdW);
CNNT_AGAIN:
switch(select(sock + 1, NULL, &fdW, NULL, &timeout)) {
case -1:
if (errno == EINTR) goto CNNT_AGAIN; /* call interrupted */
close(sock); /* select error */
exit(-1);
case 0:
close(sock);
return(-1);
default:
if (FD_ISSET(sock, &fdW)) { /* check if socket writable */
errlen = sizeof(errcode);
getsockopt(sock, SOL_SOCKET, SO_ERROR,
(char *)&errcode,&errlen);
if(errcode == 0) { /* check if connect right */
/* reset original sock flag */
if (fcntl(sock, F_SETFL, fflag) < 0) {
perror("fcntl reset file flag");
exit(-1);
}
return(sock);
} else {
close(sock);
return(-1);
}
}
}
相关文章推荐
- Socket的阻塞模式和非阻塞模式
- Socket阻塞模式和非阻塞模式的区别
- [转]Socket的阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式
- Linux UDP socket 设置为的非阻塞模式与阻塞模式区别
- Socket的阻塞模式和非阻塞模式
- I/O模式及SOCKET编程中的阻塞/非阻塞模式
- Socket 阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式
- Socket阻塞模式和非阻塞模式的区别
- I/O模式及SOCKET编程中的阻塞/非阻塞模式
- Socket 阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式
- SOCKET学习第二阶段(关于学习阻塞模式和非阻塞模式)
- Socket阻塞模式和非阻塞模式
- Socket阻塞模式和非阻塞模式的区别
- Socket 阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式
- Socket的阻塞模式和非阻塞模式