如果用TServerSocket和TClientSocket时,用的是NoBlocking方式,那如果设置超时。(10分)

  • 主题发起人 主题发起人 Boblee
  • 开始时间 开始时间
B

Boblee

Unregistered / Unconfirmed
GUEST, unregistred user!
我在大富翁上找了后知道,用Blocking后,再自定义的Thread中可以, 因为有waitfordata这个
方式,但没有人讲到用NoBlocking方式如何管理超时问题,如在联的过程中,一方(不论是,
客户端还是服务端)突然没反应或因为网络问题造成其中一方一直在连。这怎么处理?
 
呵呵,非组塞没有超时,一般来说除了connect 其他的函数都是立刻就返回
 
那怎么处理呢?总不能客户端就这样一直联接而又不能做什么。
 
我找到一篇文章,是VC的,不知对应Delphi该怎么做?

Socket中如何设置连接超时
作者:antghazi.yeah.net


  把CSDN与中文yahoo翻了底朝天,也没找到如何设置socket的连接超时的满意方法,问此问题的兄弟已有一大堆,这里偶就讲一下win下如何设置socket的connect超时。
  设置connect的超时很简单,CSDN上也有人提到过使用select,但却没有一个令人满意与完整的答案。偶所讲的也正是select函数,此函数集成在winsock1.1中,简单点讲,"作用使那些想避免在套接字调用过程中被锁定的应用程序,采取一种有序的方式,同时对多个套接字进行管理"(《Windows网络编程技术》原话)。使用方法与解释请见《Windows网络编程技术》。
  在使用此函数前,需先将socket设置为非锁定模式,这样,在connect时,才会立马跳过,同时,通常也会产生一个WSAEWOULDBLOCK错误,这个错误没关系。再执行select则是真正的超时。

WSADATA wsd;
SOCKET cClient;
int ret;
struct sockaddr_in server;
hostent *host=NULL;

if(WSAStartup(MAKEWORD(2,0),&wsd)){return 0;}
cClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(cClient==INVALID_SOCKET){return 0;}
//set Recv and Send time out
int TimeOut=6000; //设置发送超时6秒
if(::setsockopt(cClient,SOL_SOCKET,SO_SNDTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
return 0;
}
TimeOut=6000;//设置接收超时6秒
if(::setsockopt(cClient,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
return 0;
}
//设置非阻塞方式连接
unsigned long ul = 1;
ret = ioctlsocket(cClient, FIONBIO, (unsigned long*)&ul);
if(ret==SOCKET_ERROR)return 0;

//连接
server.sin_family = AF_INET;
server.sin_port = htons(25);
server.sin_addr .s_addr = inet_addr((LPCSTR)pSmtp);
if(server.sin_addr.s_addr == INADDR_NONE){return 0;}

connect(cClient,(const struct sockaddr *)&server,sizeof(server));

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

FD_ZERO(&r);
FD_SET(cClient, &r);
timeout.tv_sec = 15; //连接超时15秒
timeout.tv_usec =0;
ret = select(0, 0, &r, 0, &timeout);
if ( ret <= 0 )
{
::closesocket(cClient);
return 0;
}
//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(cClient, FIONBIO, (unsigned long*)&amp;ul1);
if(ret==SOCKET_ERROR){
::closesocket (cClient);
return 0;
}


 
楼上楼上的代码没实际用途,select容易使消息组塞,最好的办法是

while (not ClientSocket.active)or (now< 设置一个超时) do
begin
application.*****message;
end;
 
用Tevent自己设置超时,我是这样做的!
 
爱元元的哥哥,
TEvent以前一直没用过,能给个样例吗?万分感谢。
 
TEvent也可会导致消息组塞,在县城里可以用,但是在GDI界面里就不太合适
还是用Application.ProcessMessages 把,其实不用超时也是没问题,如果出错,
就在ERROR事件里写代码,如果成功,就在ClientSocket1Connect事件里写代码,
 
但如果不设超时,它能自动断开吗?
 
后退
顶部