关于connect连接超时的问题

freebeekf 2003-04-08 05:29:54
根据csdn和其他网络资源的例子,我写了如下代码,想通过select的超时来实现connect的超时,但在vc里面调试时老是出现select返回0的问题,即无法真正做到超时。
我的实现如下:
首先在一个pc上开启tcp的server,然后调试如下代码,设置超时60s,先断开连接,在10s后开启连接,但select还是返回0(超时),这样根本达不到超时connect的需求啊,可是在unix/linux下的很多示例代码也是这么写的,在csdn上antghazi的vc代码也是这样写的啊(他号称实现了超时,可是我怎么也试验不出来),请问高手怎么回事。
相关代码如下:

//设置非阻塞方式socket
unsigned long ul = 1;
int ret;
ret = ioctlsocket(SLocal, FIONBIO, (unsigned long*)&ul);
if(ret == SOCKET_ERROR)
return;

ret = connect(SLocal, (const struct sockaddr *)&Serv, sizeof(Serv));

//select 模型,即设置超时
struct timeval timeout;
fd_set r;

FD_ZERO(&r);
FD_SET(SLocal, &r);
timeout.tv_sec = 60; //连接超时60秒
timeout.tv_usec =0;

switch(select(SLocal+1, 0, &r, 0, &timeout))
{
case -1: //select fail
::closesocket(SLocal);
return;
case 0: //连接超时
::closesocket(SLocal);
return;
default: //连接成功
break;
}

//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(SLocal, FIONBIO, (unsigned long*)&ul1);
if(ret == SOCKET_ERROR)
{
::closesocket (SLocal);
return;
}

if (FD_ISSET(SLocal, &r) == 0)
return;
...全文
933 8 打赏 收藏 举报
写回复
8 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
tsdeng 2003-04-11
关注,我也在研究这问题
  • 打赏
  • 举报
回复
Richuen22 2003-04-11
请检查是否按照如此顺序,摘抄的:

---- 在Windows Sockets 编 程 中, 调 用 任 何 其 他
Winsock 函 数 以 前, 你 必 须 先 调 用WSAStartup 函
数, 使 你 的 程 序 和WINSOCK.DLL 进 行 协 调。 对 每 个
WSAStartup 函 数 调 用, 程 序 必 须 在 后 面 包 括 一
个 相 应 的WSASClean 函 数 调 用。
---- 以 上 是 一 般Winsock 编 程 的 步 骤, 由 此 建 立
的SOCKET 是 阻 塞 类 型 的, 因 此 当 建 立 的 程 序 与
远 地 主 机 进 行 通 讯 时, 如 果 远 地 主 机 能 顺 利
连 接 则 通 讯 能 正 常 进 行。 但 如 果 远 地 主 机 关
闭 或 通 讯 信 道 出 问 题 时, 你 的 程 序 就 被 阻
塞, 导 致 长 时 间 等 待, 甚 至 使 程 序 失 控。 如 果
用 非 阻 塞 类 型 的SOCKET, 编 程 人 员 就 能 自 己 确
定 与 远 地 主 机 尝 试 连 接 的 时 间, 超 过 规 定 时
间, 程 序 自 动 报 错 退 出, 很 好 的 解 决 了 使 用
阻 塞 类 型SOCKET 产 生 的 程 序 失 控 问 题。
---- 下 面 以 建 立FINGER 程 序 为 例, 介 绍 非 阻 塞
类 型 的SOCKET 的 使 用 方 法。
--- FINGER 程 序 可 以 让 你 检 索 注 册 到 一 台 主 机
上 的 每 个 人 的 名 字。 另 外,FINGER 也 可 让 你 得
到 一 个 特 定 用 户 的 公 开 信 息。 编 写 该 程 序
时, 你 可 以 学 到 怎 样 使 用FINGER 用 户 信 息 协 议
从 一 台 主 机 获 取 特 定 的 信 息。 为 了 实 现 此 目
标, 你 必 须 先 定 义 一 个SOCKET 连 接, 并 将 此
SOCKET 和 一 台 远 地 主 机 连 接 起 来。 连 接 建 立 好
以 后, 你 就 可 以 与 远 地 主 机 通 信 以 检 索 用 户
信 息。
---- 以 下 为 具 体 实 现 过 程:
---- 1、 首 先, 调 用WSAStartup 函 数 初 始 化winsock
DLL。
if(WSAStarup(WINSOCK_VERSION,&wsaData))
{
//初始化失败,报告出错
}
else{
//初始化成功,继续以后的操作
}
WSACleanup();
---- 其 中WINSOCK_VERSION 为 要 求 的winsock DLL 的 版
本 号,wsaData 中 存 储 有 关WSAStarup 函 数 返 回
的winsock DLL 的 信 息。WSAStarup 函 数 调 用 成 功 时
返 回0, 程 序 继 续 执 行, 否 则 返 回 出 错 代 码, 退
出 程 序。 程 序 结 束 时 调 用WSACleanup 函 数, 让
winsock DLL 替 程 序 释 放 所 有 分 配 的 资 源。
---- 2、winsock DLL 初 始 化 成 功 后, 程 序 调 用
socket 函 数 建 立 一 个 用 作 网 络 通 信 的socket。
hSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
其中AF_INET表示Internet地址族,在Winsock.h中定义为2。
SOCK_STREAM表示数据服务类型中的字节流服务。
IPPROTO_TCP指定TCP作为传输层协议。
---- socket 函 数 返 回 一 个socket 描 述 符, 保 存 在
hSocket 变 量 中, 该 变 量 为SOCKET 类 型。
---- 3、 调 用ioctlsocket 函 数 把socket 设 为 非 阻 塞
类 型。

iIoSocketError = ioctlsocket(hSocket,FIONBIO,&argp);
---- 其 中hSocket 就 是 前 面 建 立 的socket 描 述 符。
---- FIONBIO 为ioctlsocket 函 数 指 定 的 一 个 命 令,
当&argp 中 存 储 的 为 非 零 的 无 符 号 长 整 数 时,
hSocket 被 设 为 非 阻 塞 类 型。
---- 该 函 数 操 作 成 功 时,iIoSocketError = 0; 否 则
iIoSocketError = -1;
---- 4、socket 设 为 非 阻 塞 类 型 后, 调 用connect 函
数, 把 本 地socket 与 远 地 主 机 进 行 连 接。
iConnect = connect(hSocket,(LPSOCKADDR)
&sockAddrRemote,sizeof(sockAddrRemote));
---- 其 中hSocket 为 非 阻 塞 的socket, 利 用 该socket
与 远 地 主 机 连 接。
---- sockAddrRemote 为 包 含 远 地 主 机 地 址 信 息 的
结 构 类 型。 该 结 构 中 主 要 有 以 下 数 据 变 量:
sin_family:表示Internet地址族,值必须为AF_INET。
sin_addr :所要查询信息的远地主机的IP地址。
sin_port :端口号,在本程序中,FINGER服务协议的端口号为79。
---- 执 行connect 后, 连 接 不 能 立 即 完 成, 由 于
hSocket 为 非 阻 塞 类 型, 因 此connect 操 作 返 回 不
能 马 上 成 功, 返 回SOCKER_ERROR, 表 示 出 错, 用
WSAGetLastError 可 获 得 出 错 代 码 为WSAEWOULDBLOCK。
此 时 可 以 用select 函 数 去 查 询hSocket 是 否 为 可
读 的, 如 果 可 读, 则 说 明connect 函 数 与 远 地 连
接 成 功, 否 则 可 规 定 让select 函 数 等 待 一 段 规
定 时 间, 如 果 在 规 定 时 间 后hSocket 仍 为 不 可
读, 则 说 明 远 地 主 机 因 某 种 原 因 不 可 连 接,
程 序 安 全 结 束。 如 果 在 规 定 时 间 内hSocket 变 为
可 读, 则 说 明connect 函 数 与 远 地 连 接 成 功, 程
序 继 续 执 行。

iSelectError = select(nfds,NULL,writefds,NULL,timeout);

---- 其 中nfds 是 一 个 整 数, 用 来 与Berkeley sockets
兼 容, 可 忽 略。
---- writefds 是 一 个 指 向 fd_set 结 构 类 型 的 指
针。 可 用FD_SET 把hSocket 加 入 到writefds 所 指 的 那
个 结 构 中 去。 当select 函 数 执 行 完 成 后, 用
FD_ISSET 来 检 查writefds 中 是 否 有hSocket, 如 有 则
说 明hSocket 为 可 读, 否 则 不 可 读。

---- timeout 参 数 表 示 让select 函 数 等 待 的 最 长
时 间, 一 般1 秒 足 够, 如 果 网 络 速 度 较 慢, 可
以 设 为3--5 秒。

---- 5、 当 与 远 地 主 机 建 立 连 接 后, 可 以 开 始
向 其 发 送 数 据。
iCharSent = send(hSocket,szFingerQuery,
lstrlen(szFingerQuery),SEND_FLAGS);

---- 其 中szFingerQuery 为 向 远 地 主 机 发 送 的 字 符
串, 本 程 序 中 要 求 远 地 主 机 列 出 所 有 当 前 登
录 的 用 户, 因 此szFingerQuery 为 一 空 行。 SEND_FLAG
定 义 为 常 数0。

---- 因 为 已 确 定hSocket 为 可 读, 所 以 用send 函 数
传 送 数 据 时 不 会 出 代 码 为WSAEWOULDBLOCK 的 错
误。

---- 请 求 数 据 传 送 完 后, 便 等 待 接 收 数 据
  • 打赏
  • 举报
回复
用select可以很好地解决这一问题.大致过程是这样的:

1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完
成(有的系统用FNEDLAY也可).

2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧
在进行还没有完成.

3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,
如果可写,用
getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int));
来得到error的值,如果为零,则connect成功.
  • 打赏
  • 举报
回复
select一组描述符,好像每次必须重新设置各种初始值。
  • 打赏
  • 举报
回复
BlueSky2008 2003-04-09
另开一个线程进行connect,如果一定时间后还没完成,将其终止.
  • 打赏
  • 举报
回复
fbmsf 2003-04-09
connect会自己返回的,很快就返回了,不会一直阻塞 (in 阻塞模式 )
  • 打赏
  • 举报
回复
Sander 2003-04-08
server?
  • 打赏
  • 举报
回复
BlueSky2008 2003-04-08
up
  • 打赏
  • 举报
回复
相关推荐
发帖
网络编程

1.8w+

社区成员

VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
帖子事件
创建了帖子
2003-04-08 05:29
社区公告
暂无公告