socket网络编程,非阻塞方式重连问题

Ronal_Lee 2010-05-15 08:07:35
我的需求是:建立一个客户端socket,这个socket只用于向服务端法数据。

我需要的实现方式是:
(1)在主线程中设置成非阻塞方式去连接服务端。
(2)之后不管连接成功与否,再建立一个发送线程sendthread,这个线程中实现两个功能,一个是判断网络情况,与服务端断开时不断重连,另一个是发送数据。


long ClientTCP::Open()
{
m_Socket = ::socket(AF_INET, SOCK_STREAM, 0);

if (m_Socket == SOCKET_ERROR)
{
m_csStatus = ctDisConnect;
return -1;
}

unsigned long ulargp = 1;
int iRet = ::ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ulargp); //设置成非阻塞方式
if(SOCKET_ERROR == iRet)
{
::shutdown(m_Socket, 0);
::closesocket(m_Socket);
m_Socket = INVALID_SOCKET;
return -3;
}

sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(m_usHostPort);
addr.sin_addr.s_addr = ::inet_addr(m_strHostIp.c_str());
memset(addr.sin_zero, 0, 8);

struct timeval timeout;
fd_set rfd;

FD_ZERO(&rfd);
FD_SET(m_Socket, &rfd);
timeout.tv_sec = 3;
timeout.tv_usec =0;

connect(m_Socket, (struct sockaddr*)(&addr), sizeof(sockaddr_in));// 连接
iRet = ::select(m_Socket + 1, NULL, &rfd, NULL, &timeout); //判断套接字的写状态
if (iRet <= 0)
{

}
else
{

}


//创建发送线程
m_Terminate = false;
m_hThreadSend = ::CreateThread(NULL, 0, ThreadProcSend, this, CREATE_SUSPENDED, &m_dwThreadSendId);

if (NULL == m_hThreadSend)
{
return -2;
}
DWORD dwLastSuspendCount = ::ResumeThread(m_hThreadSend);
}


DWORD WINAPI ClientTCP::ThreadProcSend(LPVOID lpParameter)
{
CLSClientTCP* pClient = (CLSClientTCP*)lpParameter;

while (!pClient->m_Terminate)
{

struct timeval timeout;
fd_set rfd;

FD_ZERO(&rfd);
FD_SET(pClient->m_Socket, &rfd);
timeout.tv_sec = 3;
timeout.tv_usec =0;

//通过select判断写状态,进而判断与服务端是否正常连接
int iRet = ::select(pClient->m_Socket + 1, NULL, &rfd, NULL, &timeout);

//如果小于零就重连服务端,但是当我把服务端软件关闭后,上面一行的select还是返回1,这是
//为什么呀?
if (iRet <= 0)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(pClient->m_usHostPort);
addr.sin_addr.s_addr = ::inet_addr(pClient->m_strHostIp.c_str());
memset(addr.sin_zero, 0, 8);


struct timeval timeout;
fd_set rfd;

FD_ZERO(&rfd);
FD_SET(pClient->m_Socket, &rfd);
timeout.tv_sec = 3;
timeout.tv_usec =0;

connect(pClient->m_Socket, (struct sockaddr*)(&addr), sizeof(sockaddr_in));
int iRet = ::select(pClient->m_Socket + 1, NULL, &rfd, NULL, &timeout);
if (iRet <= 0)
{

continue;
}
else
{

}
}




if(pClient->m_csStatus == ctConnect)
{
// 发送数据
}

return 0;
}





我的问题是:
我的本意是通过发送线程函数的第一个select函数判断与服务端的连接状况,但是当我把服务端软件关闭后,上面一行的select仍然始终返回1,这是为什么呀?难道这样的重连方式不对吗??

求助,给分解决方法,谢谢!!!!
...全文
318 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
wesleyluo 2010-05-16
  • 打赏
  • 举报
回复
感觉逻辑上 应该是 先判断了 是否连上 才决定是要开启 发送线程,还是要重连?
AlanBruce 2010-05-16
  • 打赏
  • 举报
回复
Select 是一种静态方法,它可确定一个或多个 Socket 实例的状态。必须先将一个或多个套接字放入 IList 中,然后才能使用 Select 方法。通过调用 Select(将 IList 作为 checkRead 参数),可检查是否具有可读性。若要检查套接字是否具有可写性,请使用 checkWrite 参数。若要检测错误条件,请使用 checkError。在调用 Select 之后,IList 中将仅填充那些满足条件的套接字。

如果当前处于侦听状态,则可读意味着可成功地对 Accept 进行调用而没有阻止。如果当前已接受连接,则可读意味着有可读取的数据。这些情况下,所有的接收操作均可成功进行而没有阻止。可读性也可指示远程 Socket 是否已经关闭连接;如果连接已关闭,则对 Receive 的调用将立即返回,并返回零字节。

如果至少一个相关套接字(checkRead、checkWrite 和 checkError 列表中的套接字)符合其指定的条件,或者超过 microSeconds 参数,则无论先出现其中哪种情况,都会返回 Select。将 microSeconds 设置为 -1 会指定无限大的超时值。

如果对 Connect 进行非阻止调用,则可写意味着已经成功连接。如果已经建立连接,则可写性意味着所有的发送操作均会成功完成而没有阻止。

如果对 Connect 进行非阻止调用,则 checkerror 参数将标识尚未成功连接的套接字。
AlanBruce 2010-05-16
  • 打赏
  • 举报
回复
使用异步socket

在ACE中,异步连接是很方便的。。
yanran_hill 2010-05-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 ronal_lee 的回复:]
那为什么服务端软件已经关闭了,socket也就中断了,而select依然返回“写状态已经准备好”呢?

[/Quote]
我认为这一句有疑问,当然这有点跑题了,与楼主的题目关系不大,TCP关闭需要进行4次操作,才能保证双向通信的关闭.
"服务器端关闭",这一句的判断依据,应该是远端(假定是远端开始主动关闭)发出了Close,也就是一个fin,这时候,远端的操作系统将拒绝调用者继续向socket写数据,但是已经写到socket缓冲区等待发送的数据,将会继续发送(或者丢掉),本地端在收到这个fin之后,会回送一个ACK通知远端,远端收到后,将不再接收数据
因此,服务器端软件关闭了,可是不见得socket会中断,这时候对这个socket进行select,应该会发现读操作和写操作都可能是允许的,只不过read操作会立即返回0字节,写操作的结果还不能确定
说得简单一些,就是当远端用户调用 close函数的时候,本地能通过read返回0(不再阻塞),得知对方已经关闭,然后本地用户应该调用close,这时socket才算是关闭了
mengde007 2010-05-16
  • 打赏
  • 举报
回复
可以定期发送一个数据;让对方返回一个ACK
Ronal_Lee 2010-05-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 mengde007 的回复:]
select只是反映出这个socket与某个集合的关系的状态;
即便是中断了,这个socket依然存在,最好先判断这个socket是否能通;
[/Quote]

我这种 非阻塞 的方式,在那个线程中怎么判断与服务器的连接状态、并且重连呢?
mengde007 2010-05-15
  • 打赏
  • 举报
回复
select只是反映出这个socket与某个集合的关系的状态;
即便是中断了,这个socket依然存在,最好先判断这个socket是否能通;
Ronal_Lee 2010-05-15
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 mengde007 的回复:]
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred.
通过select看与……
[/Quote]

那为什么服务端软件已经关闭了,socket也就中断了,而select依然返回“写状态已经准备好”呢?

这个我不太懂,给解释一下吧,谢谢
mengde007 2010-05-15
  • 打赏
  • 举报
回复
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred.
通过select看与服务器的连接?它没这个功能,这个要看connect的返回值即可判断;
Ronal_Lee 2010-05-15
  • 打赏
  • 举报
回复
求助啊…………

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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