公布: CSOCKET的超时设置和UDP发送接收

dasiu 2006-04-20 10:27:31
详细进入:
最近需要用到UDP广播,在程序设计中发现了不少问题,写出来和大家分享。
http://blog.csdn.net/mrxwh/archive/2006/04/19/669338.aspx
...全文
424 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
templarzq 2006-06-14
  • 打赏
  • 举报
回复
不过我不太明白楼主为什么死盯着CSocket而不考虑asynselect 等异步模型呢?
templarzq 2006-06-14
  • 打赏
  • 举报
回复
多谢,学到几个东西。
peekmessage
QueryPerformanceCounter
CancelBlockingCall

xinyu 2006-06-14
  • 打赏
  • 举报
回复
正找这方面的资料,谢谢!
kingzai 2006-04-20
  • 打赏
  • 举报
回复
不错!mrxwh共享自己经验的做法值得鼓励。
dasiu 2006-04-20
  • 打赏
  • 举报
回复
希望对UDP使用者有所帮助
dasiu 2006-04-20
  • 打赏
  • 举报
回复
使用CSoket多次了,但对于它的block模式的理解并不是很深入。昨天使用csoket的udp多发测试(server接到数据后,需要通过某种方式将数据发送到client,使用tcp方式比较可靠,我一直这样用的,但是比较费时,需要逐一发送),发现了问题:

1)create(),sendto(),receivefrom()....

2)其中,发送方一直定时发送数据无问题;

3)而接收方,通过一个单独的接收线程实现( 注意:csocket不能跨线程使用!主线程中socket create()后,detach()并将sock作为lpvoid传入接收线程 )。代码如下:

//处理接收数据
UINT CSockSvr::DealSvrRevData(LPVOID lParam)
{

......
DWORD dwError;
TCHAR cBuff[1000];
CString sIP;
UINT uPort;
for(;!pDlg->m_bExit;)
{
::memset( cBuff,0,sizeof(cBuff) );

// 如果没有接到数据,一直等待。。。。
// 阻塞模式的弊端:::在退出时候,通过CancelBlockingCall
int iRst=SockSvr.ReceiveFrom( cBuff,sizeof(cBuff),sIP,uPort,0 );
if( iRst!=SOCKET_ERROR )
{
CString sTemp=cBuff;
TRACE1( _T("\r\n Rev Data: %s\r\n"),sTemp );
}
else
{
dwError=GetLastError();
TRACE1( _T("\r\n Rev Data Error code: %d\r\n"),dwError );
}
::Sleep(200);
}

return 0;
}

问题:如果发送方没有数据,SockSvr.ReceiveFrom()会一致处于等待状态,导致整个处理接收线程的停止,如果用户需要退出/结束程序,无法正确释放资源(无法关闭在线程函数重打开的socket--不能跨线程操作socket,无法关闭线程),造成系统memory leak...

针对这种问题,微软的解决办法是:http://support.microsoft.com/default.aspx?scid=kb;zh-cn;138692 ,经过测试,在socket进行connect()的时候不好用。后来,结合微软的办法,我通过自定义的定时器,实现了block超时间后自动退出的功能〉

#if !defined(AFX_TIMEOUTSOCK_H__19897A81_4EAF_4005_91FD_DC3047725139__INCLUDED_)
#define AFX_TIMEOUTSOCK_H__19897A81_4EAF_4005_91FD_DC3047725139__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// TimeOutSock.h : header file
//

/*
CSocket 操作,如接收(Receive)、发送(Send) 和连接(Connect) 均是阻塞操作,
即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。
某些情况下,操作可能永远不能成功完成,这将导致程序无限循环等待操作完成。
一种解决方法是通过编程限制完成操作使用的时间。本文将讨论这种方法。
*/
/////////////////////////////////////////////////////////////////////////////
// CTimeOutSock command target

class CTimeOutSock : public CSocket
{
// Attributes
public:

// Operations
public:
CTimeOutSock();
virtual ~CTimeOutSock();

// Overrides
public:
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTimeOutSock)
public:
virtual BOOL OnMessagePending();
//}}AFX_VIRTUAL

// Generated message map functions
//{{AFX_MSG(CTimeOutSock)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG

/*
//定时器设置block超时 不是很好用。。。徐卫话 2006.4.19
CSocket 操作,如接收(Receive)、发送(Send) 和连接(Connect) 均是阻塞操作,
即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。
某些情况下,操作可能永远不能成功完成,这将导致程序无限循环等待操作完成。
一种解决方法是通过编程限制完成操作使用的时间。本文将讨论这种方法。
*/
// 自己计算时间的办法 OK
public:
BOOL SetTimeOut(UINT uTimeOut=1000);
BOOL KillTimeOut();
private:
LONGLONG m_llDtStart;
UINT m_uTimeOut;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_TIMEOUTSOCK_H__19897A81_4EAF_4005_91FD_DC3047725139__INCLUDED_)


// TimeOutSock.cpp : implementation file
//

#include "stdafx.h"
#include "NetBroad.h"
#include "TimeOutSock.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTimeOutSock

CTimeOutSock::CTimeOutSock()
{

}

CTimeOutSock::~CTimeOutSock()
{
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CTimeOutSock, CSocket)
//{{AFX_MSG_MAP(CTimeOutSock)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0

/////////////////////////////////////////////////////////////////////////////
// CTimeOutSock member functions

//设置超时
BOOL CTimeOutSock::SetTimeOut(UINT uTimeOut)
{
//get start cnt
LARGE_INTEGER llCnt;
::QueryPerformanceCounter(&llCnt);
m_llDtStart=llCnt.QuadPart;
m_uTimeOut=uTimeOut;

return TRUE;
}

//删除超时参数
BOOL CTimeOutSock::KillTimeOut()
{
m_llDtStart=0;//表明取消计时
return TRUE;
}

//检查是否超时间
BOOL CTimeOutSock::OnMessagePending()
{
// TODO: Add your specialized code here and/or call the base class
/*
MSG msg;
if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE))
{
if (msg.wParam == (UINT) m_nTimerID)
{
// Remove the message and call CancelBlockingCall.
::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
CancelBlockingCall();
return FALSE; // No need for idle time processing.
};
};
*/
if( m_llDtStart )
{
LARGE_INTEGER lldtEnd;
::QueryPerformanceCounter(&lldtEnd);
LARGE_INTEGER llFrq;
::QueryPerformanceFrequency(&llFrq);
double dbDealy=(double)(lldtEnd.QuadPart-m_llDtStart)*1000/llFrq.QuadPart;
if( dbDealy>m_uTimeOut )
{
CancelBlockingCall();
return FALSE; // No need for idle time processing.
}
}

return CSocket::OnMessagePending();
}



经过改进后, 对处理接收线成的函数进行了部分改进:

SockSvr.SetTimeOut(500); int iRst=SockSvr.ReceiveFrom( cBuff,sizeofcBuff),sIP,uPort,0 ); SockSvr.KillTimeOut();

当block超过定时后,socket自动退出block,防止接收线程停止。问题终于解决了!






18,356

社区成员

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

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