阻塞方式下实现socket连接超时控制(不用select)

DDGG 2010-01-27 11:58:13
众所周知,阻塞模式下进行TCP连接,当连接不上的时候,其等待时间是未知的。
为了让这个连接的超时时间变得可控,绝大多数代码采取了先将socket置为非阻塞,用select进行超时判别,其后再根据需要设置socket为阻塞模式的方法。
但是我觉得既然在阻塞方式下send和recv函数的超时都可以进行设置而变得可控,那connect函数也应该可以才对。

看到这里大家应该知道这是篇纯技术的讨论了哈,不适合“为达目的不择手段,先混过去再说”的玩家。

在网上找到一篇http://www.rtems.com/ml/rtems-snapshots/2000/september/msg00004.html,看起来很有希望的样子,但是我用VC6建了一个控制台程序测试却失败了。特此请教在socket领域涉足较深的朋友,解决这个问题在理论上是否可行?如果可行,那我的代码有什么问题?还是说那篇文章代码的运行条件是在linux下才可以?谢谢!

// Test0127.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "winsock2.h"
#include "stdlib.h"
#pragma comment(lib, "ws2_32.lib")

class CWSAInit
{
public:
CWSAInit()
{
WSADATA wsaData;
m_bFailed = WSAStartup(MAKEWORD(2, 2), &wsaData) != 0;
}

~CWSAInit()
{
WSACleanup();
}

BOOL Failed() const { return m_bFailed; }

private:
BOOL m_bFailed;
};


int main(int argc, char* argv[])
{
CWSAInit wsa;
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in sa;
struct hostent *he;
int nRet;

if (wsa.Failed())
{
return -1;
}

// initialize socket
he = gethostbyname("192.168.1.200"); // 地址
if (he == NULL)
{
return -1;
}

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
return -1;
}

// set connect timeout
timeval tvOld, tvNew;
int ntvlen = sizeof timeval;

tvNew.tv_sec = 3; // 3秒
tvNew.tv_usec = 0;
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvOld, &ntvlen) == SOCKET_ERROR)
{
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvNew, sizeof timeval) == SOCKET_ERROR)
{
return -1;
}
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvOld, &ntvlen) == SOCKET_ERROR) // 读出来的 tvOld.tv_usec 不为 0?
{
return -1;
}

printf("connecting...\n");

// connect
sa.sin_family = AF_INET;
sa.sin_port = htons(80); // 端口
sa.sin_addr = *((struct in_addr *)he->h_addr);

nRet = connect(sock, (struct sockaddr *)&sa, sizeof(sockaddr)); // 应只在3秒内尝试连接
if (nRet == SOCKET_ERROR)
{
printf("connect error!\n");
}
else
{
printf("connect ok!\n");
}
closesocket(sock);

system("pause");

return 0;
}


...全文
1314 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
DDGG 2010-02-22
  • 打赏
  • 举报
回复
研究结果就是——没有办法,那个老外纯属忽悠。╮(╯_╰)╭
lyserver 2010-02-09
  • 打赏
  • 举报
回复
可以只对connect动作进行非阻塞,然后再还原为阻塞
hEvent = WSACreateEvent();
WSAEventSelect(s, hEvent, FD_CONNECT); //设置事件监听,只监听FD_CONNECT
dwStartTime = GetTickCount();
while(GetTickCount() - dwStartTime < 1000) //超时1秒
{
//检测网络事件,以判断是否连接成功
WSAWaitForMultipleEvents(...
}
WSAEventSelect(s, NULL, 0); //取消事件监听
ioctlsocket(... //设置为阻塞
//后面使用阻塞方式进行通讯
wb112200 2010-02-09
  • 打赏
  • 举报
回复
期待楼主的研究结果,楼主可以更深入的了解下,也期待高手给个解决方法》。。。
DDGG 2010-02-08
  • 打赏
  • 举报
回复
难道老外的那篇帖子纯属忽悠?过年前我会结了这帖的!
edifier 2010-02-07
  • 打赏
  • 举报
回复
楼主说的“为了让这个连接的超时时间变得可控,绝大多数代码采取了先将socket置为非阻塞,用select进行超时判别,其后再根据需要设置socket为阻塞模式的方法。 ”正解。
我就是这样实现的,已在vxworks、win32、linux下下分别实现。
Conry 2010-01-29
  • 打赏
  • 举报
回复
非要用阻塞的话,只能是另起一个线程来控制了,超时就直接closesocket
sanguomi 2010-01-28
  • 打赏
  • 举报
回复
SO_RCVTIMEO 这函数一般都用在非阻塞的过程中,在阻塞的函数调用中作用不大
YODOYODO 2010-01-27
  • 打赏
  • 举报
回复
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvOld, &ntvlen) == SOCKET_ERROR)
{
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvNew, sizeof timeval) == SOCKET_ERROR)
{
return -1;
}
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tvOld, &ntvlen) == SOCKET_ERROR) // 读出来的 tvOld.tv_usec 不为 0?
{
return -1;
}


这跟连接超时有什么关系呢?
Henry8484 2010-01-27
  • 打赏
  • 举报
回复
UP~~~
奔跑前行 2010-01-27
  • 打赏
  • 举报
回复
差不多是没希望了。。。。。呵呵。。。不过继续研究socket倒是不错的
DDGG 2010-01-27
  • 打赏
  • 举报
回复
哦,难道没有希望了么?
bragi523 2010-01-27
  • 打赏
  • 举报
回复
阻塞的connect并不能设置超时
要想实现的话
你可以自己封装啊
封装个lib出来以后就可以用了
WizardK 2010-01-27
  • 打赏
  • 举报
回复
仅看对getsockopt和setsockopt的使用,应该是get后,修改,再set这个顺序。
WizardK 2010-01-27
  • 打赏
  • 举报
回复
SO_RCVTIMEO and SO_SNDTIMEO
When using the recv function, if no data arrives during the period specified in SO_RCVTIMEO, the recv function completes. In Windows versions prior to Windows 2000, any data received subsequently fails with WSAETIMEDOUT. In Windows 2000 and later, if no data arrives within the period specified in SO_RCVTIMEO the recv function returns WSAETIMEDOUT, and if data is received, recv returns SUCCESS.
If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used; TCP sockets in this state have a potential for data loss, since the operation could be canceled at the same moment the operation was to be completed.

没有看到提到了CONNECT函数
不动如岳 2010-01-27
  • 打赏
  • 举报
回复
有时间研究研究还是很不错的。
c_s0001 2010-01-27
  • 打赏
  • 举报
回复
connect函数好像不行
YODOYODO 2010-01-27
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 ddgg 的回复:]
呵呵,非阻塞、select都麻烦啊,难道大家不想让代码尽量简单?
是有点钻牛角尖,所以我开头都说了,纯研究,哈哈
[/Quote]

事实上,我们有多少机会从头写一个socket程序?像这些东西,早就封装好了哪还有什么麻烦?
DDGG 2010-01-27
  • 打赏
  • 举报
回复
呵呵,非阻塞、select都麻烦啊,难道大家不想让代码尽量简单?
是有点钻牛角尖,所以我开头都说了,纯研究,哈哈
hurryboylqs 2010-01-27
  • 打赏
  • 举报
回复
钻牛角尖
rainsly 2010-01-27
  • 打赏
  • 举报
回复
印象中SO_RCVTIMEO只是接收超时,不太清楚是否能够影响connect
另外connect好像有个超时重试一说,重试次数不确定能否设置

期待楼主的研究结果
加载更多回复(1)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧