1
我正在玩跨平台框架中的套接字层,我试图让连接以非阻塞方式工作。然而,在翻阅文档之后,他们似乎根本没有正确的表现。问题的核心在于,在启动非阻塞之后,请连接以下选择失败以注意连接已成功并一再重复超时。非阻塞连接上的MacOSX select()行为不正确
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
hostent *h = gethostbyname("www.memecode.com");
if (h)
{
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
if (h->h_addr_list && h->h_addr_list[0])
{
memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(in_addr));
// Set non blocking
fcntl(s, F_SETFL, O_NONBLOCK);
int64 start = LgiCurrentTime();
int status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
printf("Initial connect = %i\n", status);
while (status && (LgiCurrentTime()-start) < 15000)
{
// Do select to wait for connect to finish
fd_set wr;
FD_ZERO(&wr);
FD_SET(s, &wr);
int TimeoutMs = 1000;
struct timeval t = {TimeoutMs/1000, (TimeoutMs % 1000) * 1000};
errno = 0;
int64 sel_start = LgiCurrentTime();
int ret = select(0, 0, &wr, 0, &t);
int64 sel_end = LgiCurrentTime();
printf("%i = select(0,%i,0) errno=%i time=%i\n",
ret,
FD_ISSET(s, &wr)!=0,
errno,
(int)(sel_end-sel_start));
if (ret > 0 && FD_ISSET(s, &wr))
{
// ready for connect to finish...
status = connect(s, (sockaddr*) &addr, sizeof(sockaddr_in));
printf("2nd connect = %i\n", status);
if (status)
{
if (errno == EISCONN)
{
status = 0;
printf("error = EISCONN so we're good.\n");
}
}
}
// else still waiting...
}
}
else printf("host addr error.\n");
}
else printf("gethostbyname failed.\n");
当我运行MacOSX上的最新豹构建这个代码我得到这样的输出:
Initial connect = -1
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1001
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
0 = select(0,1,0) errno=0 time=1000
当我经过选择删除“RET> 0”的情况下连接成功并返回EISCONN。所以连接在幕后工作,但选择从不接受。根据我对选择返回值的理解,它包含fd_set结构中的套接字数量,如果没有事件发生,则返回0。
我的代码有什么问题?
PS LgiCurrentTime()从某点开始返回毫秒,例如, GetTickCount在Windows上......我忘记了Mac上的确切实施,但它并不重要......只是计时信息。
咦......那好吧......最快的答案永远!我是来自窗户的难民,在那个平台上,第一个参数完全被忽略。 Thx快速回复。 – fret 2009-08-08 22:27:26
Ha;)在这个问题中看到“meme”也很有趣。我的公司名为Memention - http://memention.com – epatel 2009-08-08 22:31:32