也问一个API + SOCKET 阻塞超时处理的问题

rudolf_he 2006-01-10 03:18:39
服务器端线程代码如下:

void __fastcall TCommunication::Execute()
{
char buf[4096];
int nSize=0;
int i = 0;
while(1)
{

nSize = recv(m_AcceptSocket, (char FAR*)buf, 4096, 0);//问题1

if(nSize>0)
{
buf[nSize] = '\0';
//Display
PSTNForm->Memo1->Lines->Add("Received Length:" + String(nSize));
PSTNForm->Memo1->Lines->Add("Received:" + StrPas(buf));
//Deliver
::Sleep(100);
send(m_AcceptSocket, buf, nSize, 0);
}
else
{ //问题2
i++;
if (10 < i)
{
break;
}
}
}
}

问题1:
nSize = recv(m_AcceptSocket, (char FAR*)buf, 4096, 0);
这句,如果没有数据接收到那么 recv 将一直等下去,是吗?
如果我想设定一个超时处理应该怎么做呢?

问题2:
为什么要加这个循环?
防止误操作吗?

谢谢!!
...全文
474 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
rudolf_he 2006-02-16
  • 打赏
  • 举报
回复
分不多。

谢谢各位的指点。
nancy_yan 2006-01-25
  • 打赏
  • 举报
回复
if (connect(m_clientSockect,(struct sockaddr *)&Socket_Addr,sizeof(Socket_Addr))!=0 )当Socket连接出错时,这个返回时间好像要30秒左右,能不能有参数设置这个超时时间呢?
痞子酷 2006-01-25
  • 打赏
  • 举报
回复
WINDOWS我给一个完整的代码:
//关闭socket连接
void T125855SocketUnit::CloseSocket()
{
closesocket(m_clientSockect);
WSACleanup();
}
//建立socket连接
int T125855SocketUnit::ConnectSocket()
{
long ret;
SOCKADDR Socket_Addr;
SOCKADDR_IN Socket_Addr_in;

WORD Version =0x0002;
WSADATA WSDATA;
WSAStartup(Version,&WSDATA);

//创建SOCKET
m_clientSockect=socket(AF_INET,1,0);
if(m_clientSockect==INVALID_SOCKET){
mErrInfo="创建Socket出错!";
return -1;
}
Socket_Addr_in.sin_family=AF_INET;
Socket_Addr_in.sin_port=htons(mSockPort);
Socket_Addr_in.sin_addr.s_addr=inet_addr(mIPaddress);
memcpy(&Socket_Addr,&Socket_Addr_in,sizeof(SOCKADDR_IN));

//建立连接
if (connect(m_clientSockect,(struct sockaddr *)&Socket_Addr,sizeof(Socket_Addr))!=0 ){
mErrInfo="Socket连接出错!";
return -2;
}


fd_set readfds;
char strBuff[102400];
struct timeval tv;

tv.tv_sec = mSockTimeOut; //30秒
tv.tv_usec = 0;
FD_ZERO(&readfds);

FD_SET(m_clientSockect,&readfds);
switch (select(sockfd + 2, &fdR, NULL, NULL, &timeout ))
{
case -1:
return -1;
case 0:
return 0;
default:
if (FD_ISSET(fd1, &fdR))
{
iLen=read(fd1, tmpBuf, 1024);
if(iLen<=0) return 0;
write(fd2, tmpBuf, iLen);
}
if (FD_ISSET(fd2, &fdR))
{
iLen=read(fd2, tmpBuf, 1024);
if(iLen<=0) return 0;
write(fd1, tmpBuf, iLen);
}
}
return 0;
}
rudolf_he 2006-01-25
  • 打赏
  • 举报
回复
先谢谢楼上二位的答复。

TO ouygg(痞子酷) 你的代码我重新排版了一下,不过还是没看大明白,不知你是否有空能再写点简单的说明?
谢谢!!

struct timeval timeout = ..;
//struct timeval {
// int tv_sec; /* seconds */
// int tv_usec; /* microseconds */
//
sockfd = fd1;
if(fd1 < fd2) sockfd = fd2;

FD_ZERO(&fdR);
FD_SET(fd1, &fdR);
FD_SET(fd2, &fdR);

switch (select(sockfd + 2, &fdR, NULL, NULL, &timeout ))
{
case -1:
return -1;
case 0:
return 0;
default:
if (FD_ISSET(fd1, &fdR))
{
iLen=read(fd1, tmpBuf, 1024);
if(iLen<=0) return 0;
write(fd2, tmpBuf, iLen);
}
if (FD_ISSET(fd2, &fdR))
{
iLen=read(fd2, tmpBuf, 1024);
if(iLen<=0) return 0;
write(fd1, tmpBuf, iLen);
}
FD_CLR(fd1, &fdR);
FD_CLR(fd2, &fdR);
}
return 1;
痞子酷 2006-01-25
  • 打赏
  • 举报
回复
setsockopt好像可以实现,很以后我们很仔细研究过。
痞子酷 2006-01-24
  • 打赏
  • 举报
回复
如果采用SOCKET API的话,可以使用SELECT来实现
我贴一个unix下一段参考代码:
struct timeval timeout = ..;
//struct timeval {
// int tv_sec; /* seconds */
// int tv_usec; /* microseconds */
//
sockfd=fd1;
if(fd1<fd2)
sockfd=fd2;


FD_ZERO(&fdR);
FD_SET(fd1,&fdR);
FD_SET(fd2,&fdR);
switch (select(sockfd + 2, &fdR, NULL, NULL,&timeout ))
{
case -1:
return -1;
case 0:
return 0;
default:
if (FD_ISSET(fd1,&fdR))
{
iLen=read(fd1,tmpBuf,1024);
if(iLen<=0)
return 0;
write(fd2,tmpBuf,iLen);
}
if (FD_ISSET(fd2,&fdR))
{
iLen=read(fd2,tmpBuf,1024);
if(iLen<=0)
return 0;
write(fd1,tmpBuf,iLen);
}
FD_CLR(fd1,&fdR);
FD_CLR(fd2,&fdR); } return 1;
glassegg 2006-01-20
  • 打赏
  • 举报
回复
用setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

void __fastcall TCommunication::Execute()
{
SOCKET sock =socket(AF_INET, SOCK_DGRAM,0);
int nNetTimeout=1000;//1秒
int ret =
setsockopt(sock,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

char buf[4096];
int nSize=0;
int i = 0;
while(1)
{

nSize = recv(m_AcceptSocket, (char FAR*)buf, 4096, 0);//问题1
// 1 s later timeout
if(nSize>0)
{
buf[nSize] = '\0';
//Display
PSTNForm->Memo1->Lines->Add("Received Length:" + String(nSize));
PSTNForm->Memo1->Lines->Add("Received:" + StrPas(buf));
//Deliver
::Sleep(100);
send(m_AcceptSocket, buf, nSize, 0);
}
else
{ //问题2
i++;
if (10 < i)
{
break;
}
}
}
}
question 2
answer:
因为受信线程是要持续rcv的,如果没有while,则线程只能运行一次便结束了,无法连续接受数据



「已注销」 2006-01-14
  • 打赏
  • 举报
回复
学习
CCED136 2006-01-11
  • 打赏
  • 举报
回复
如果 m_AcceptSocket 是一个阻塞型的 socket ,则

1、recv 将在下列情况发生时返回(对方关闭了 socket / recv 操作被取消 /
m_AcceptSocket 被关闭),否则将一直等待数据的到来。
阻塞型 socket ,可以使用 select 进行超时控制,具体的参考有关 WINSOCKET API 说明。

2、这里的循环 while(1) {...},主要是为了完成不停的信息转发功能,并且提供了 10 次容错
支持。

就个人意见,tcp 协议已经完成了绝大部分的容错机制,tcp 会自动地完成相关的重传
重组等功能,这里的 10 次容错功能其实根本没有必要,并且也不可靠,因为当第一次
错误发生时,后续通讯行为的正确性将没有任何保证,通讯的双方如果需要进行应用逻
辑同步的话,基本上来说是非常困难的,除非像 ftp 一样,使用两个连接,一个控制,
一个数据。
rudolf_he 2006-01-11
  • 打赏
  • 举报
回复
回复以后才看得到,算不算论坛的BUG?
rudolf_he 2006-01-11
  • 打赏
  • 举报
回复
晕,怎么看不到我的帖子?

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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