CSDN博客

img jmcooler

一个管理监听、连接、发送、接收、组包的CSocket派生类

发表于2004/6/28 13:27:00  3354人阅读

简介:

    CAdmitSocket,从CSocket派生,它比CSocket增加的内容就是管理Accept后的Socket连接,重新定义Send函数。管理接收数据并组包,并在收到整包数据后,调用OnRecResponse(  LPBYTE, int )虚函数。

使用要点:

    你所使用的Socket必须从CAdmitSocket派生,并重载OnRecResponse()、OnSocketClose()。你可能需要重载OnAcceptSocket()。其中:

OnRecResponse()  : 当收到一个整包数据时,被调用。

OnAcceptSocket() :  表明一个客户连接已经被Accept。

OnSocketClose()   :  被接受的Socket已经关闭时,它和OnAcceptSocket()正好相反。

    你的派生类(假设为CMySocket)必须声明DECLARE_DYNCREATE(CMySocket)和IMPLEMENT_DYNCREATE(CMySocket,CAdmitSocket)。

    CPackHead是包头信息,其中字段:

            WORD    m_PackFlag;   //包标志,自定义的。

            UINT       m_PackSize;   //包长度,包括包头长度和数据长度

   如果你并不想要使用这个类,你也可以参照这个类的源代码,写你自己的Socket代码。

   附加:

   关于CSocket、CAsyncSocket使用的几点注意,否则将导致不必要的麻烦:
1、CSocket及其基类CAsyncSocket采用Windows消息机制,即Socket事件通过Post消息方式发往内建的窗口,并在该窗口内调用虚函数OnAccept()、OnConnect()、OnSend()、OnReceive()和OnClose()等,所以CSocket所在的线程必须要有消息循环。
2、一个CSocket对象要在多个线程里传递时,不能直接传递(指针)。因为CSocket被尽力设计为线程安全的,它的内部句柄m_hSocket同一时刻只能被一个线程拥有。因此,在线程间应该传递句柄而不是指针。方法是:当前拥有CSocket对象的线程先Detach(),然后将返回的句柄传给另一线程。在另一线程中,再Attach()。
3、CSocket在多线程中使用时,请对VS6.0打SP5。因为不打SP5和打SP5,AfxSockInit()函数的内部实现源代码是不同的。而后者则支持多线程。并且每个用到CSocket的线程,请都调用AfxSockInit()
4、对一次OnReceive()事件,请将Socket内部缓冲区的到达数据接收完,否则可能导致以后OnReceive()不再触发。原因是:OnSend()、OnReceive()都是当缓冲区从有到无或者从无到有数据才触发的。
5、Socket内部的默认缓冲区大小一般是4096或者8192,默认值大小特性是我们关注的,虽然不必要知道究竟有多大,但得知道有这么个特性,因此,除非是一应一答的通信,你应该在发送和接收时组包(包括自己定义包的边界和标志等信息)。

     头文件:AdmitSocket.h

#if !defined(AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_)
#define AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <afxsock.h>
#include <afxtempl.h>

#ifdef _AFX_PACKING
#pragma pack(push, _AFX_PACKING)
#endif

//有关文件数据传输的Socket包结构和数据定义
#define   LISTENPORT1          3210   //Thales发送使用的Socket端口
#define   LISTENPORT2          3215   //和大调度通信的默认端口


typedef struct CPackHead {
 WORD    m_PackFlag;
 UINT    m_PackSize;
} CPackHead;

class CAdmitSocket : public CSocket
{
 DECLARE_DYNCREATE(CAdmitSocket)
public:
 CAdmitSocket();
 virtual ~CAdmitSocket();

 virtual void OnAcceptSocket( CAdmitSocket* pAcceptSock );
 virtual void OnSocketClose();
 virtual void OnRecResponse( LPBYTE, int );

 static CTypedPtrArray<CObArray,CAdmitSocket*>  s_SockArray;

 BOOL   Listen( int nPort = 0 );
 virtual void OnAccept(int nErrorCode);

 virtual void Close();

 BOOL    m_bListen;

 BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort = 0 );
 BOOL Send( WORD nPackFlag, const void* lpBuf, int nBufLen );


public:
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAdmitSocket)
 public: 
 virtual void OnReceive(int nErrorCode);
 virtual void OnClose(int nErrorCode);
 //}}AFX_VIRTUAL

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

// Implementation
protected:
 UINT    m_nBufSize;
 LPBYTE  m_pRecDataBuf;
 UINT    m_nPrevDataSize;
// CPackHead  m_PackHead;
};

inline void CAdmitSocket::OnRecResponse( LPBYTE, int )
{
}

inline void CAdmitSocket::OnAcceptSocket( CAdmitSocket* pAcceptSock )
{
}

inline void CAdmitSocket::OnSocketClose()
{
}


#ifdef _AFX_PACKING
#pragma pack(pop)
#endif

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

#endif // !defined(AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_)

执行文件:AdmitSocket.cpp

#include "stdafx.h"
#include "AdmitSocket.h"

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

//#define  RECBUF_SIZE   10000

IMPLEMENT_DYNCREATE(CAdmitSocket, CSocket)

CTypedPtrArray<CObArray,CAdmitSocket*>  CAdmitSocket::s_SockArray;

CAdmitSocket::CAdmitSocket():m_pRecDataBuf(NULL),m_nPrevDataSize(0)
{
       m_bListen       = FALSE;
       m_nBufSize      = 0;
}

CAdmitSocket::~CAdmitSocket()
{
      if( m_hSocket != INVALID_SOCKET )
           CSocket::Close();
      if( m_pRecDataBuf != NULL )
     {
          delete []m_pRecDataBuf;
          m_pRecDataBuf = NULL;
     }
}


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

void CAdmitSocket::OnReceive(int nErrorCode)   //服务器方的接收
{
      if( nErrorCode != 0 )
     {
          ASSERT( FALSE );
          return;
     }

     int         nRec;
     DWORD       dwBytes = 0;
     CPackHead*  pPackHead;
     UINT        nOffset = 0, nHeadSize = sizeof( CPackHead );
     if( !IOCtl( FIONREAD, &dwBytes ) )
    {
         dwBytes = GetLastError();
         if( dwBytes == WSAENETDOWN || dwBytes == WSAENOTSOCK )
              Close();
         return;
    }
    if( dwBytes == 0 )
    {
        ASSERT( FALSE );
        return;
    }
    if( dwBytes+m_nPrevDataSize > m_nBufSize )
   {
        LPBYTE pTmpBuf = new BYTE[dwBytes+m_nPrevDataSize];
        if( m_pRecDataBuf != NULL )
       {
             memcpy( pTmpBuf, m_pRecDataBuf, m_nPrevDataSize );
             delete []m_pRecDataBuf;
        }
        m_pRecDataBuf = pTmpBuf;
        m_nBufSize    = dwBytes+m_nPrevDataSize;
   }
 nRec = Receive( m_pRecDataBuf + m_nPrevDataSize, dwBytes );
 if( nRec <= 0 )
 {
  Close();
  return;
 }
 m_nPrevDataSize += nRec;
 while( m_nPrevDataSize > nHeadSize )
 {
  pPackHead = (CPackHead*)(m_pRecDataBuf+nOffset);
  if( m_nPrevDataSize < pPackHead->m_PackSize )
   break;
  OnRecResponse( (LPBYTE)pPackHead, pPackHead->m_PackSize );
  m_nPrevDataSize -= pPackHead->m_PackSize;
  nOffset += pPackHead->m_PackSize;
 }
 if( nOffset > 0 && m_nPrevDataSize > 0 )
  memcpy( m_pRecDataBuf, m_pRecDataBuf+nOffset, m_nPrevDataSize );

 

 

/* if( nErrorCode != 0 )
 {
  ASSERT( FALSE );
  return;
 }

 TRACE( _T("OnReceive(),准备接收:/n") );
 int nPackSize, nHeadSize = sizeof( m_PackHead );
 int nRecCount = Receive( &m_PackHead, nHeadSize );
 if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
 {
  Close();
  ASSERT( FALSE );
  return;
 }
 TRACE( _T("开始收到%d字节/n"), nRecCount );
 nPackSize = nRecCount;
 while( nPackSize < nHeadSize )
 {
  nRecCount = Receive( ((char*)(&m_PackHead))+nPackSize, nHeadSize-nPackSize );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
  {
   Close();
   ASSERT( FALSE );
   return;
  }
  nPackSize += nRecCount;
 }

 TRACE( _T("收到包头%d字节,总包长=%d/n"), nPackSize, m_PackHead.m_PackSize );

 LPBYTE pDataBuf = new BYTE[m_PackHead.m_PackSize];
 memcpy( pDataBuf, (char*)&m_PackHead, nHeadSize );
 while( (UINT)nPackSize < m_PackHead.m_PackSize )
 {
  nRecCount = Receive( pDataBuf + nPackSize, m_PackHead.m_PackSize - nPackSize );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
  {
   Close();
   ASSERT( FALSE );
   return;
  }
  nPackSize += nRecCount;
 }
 TRACE( _T("收到整包%d字节,进行处理!/n"), nPackSize );
 ASSERT( nPackSize == m_PackHead.m_PackSize );
 OnRecResponse( pDataBuf, m_PackHead.m_PackSize );
 delete []pDataBuf;
 DWORD dwBytes = 0;
 if( IOCtl( FIONREAD, &dwBytes ) && dwBytes > 0 )
 {
  TRACE( _T("Socket内部还有%d字节没有收,继续.../n"), dwBytes );
  OnReceive( 0 );
 }*/

/* if( nErrorCode != 0 )
  return;
 int     nPackSize, nRecCount;
 DWORD   nBytes = 0;
 if( m_nPrevDataSize == 0 )
 {
  CPackHead   phs;   
  int         nHeadSize = sizeof(phs);
  if( !IOCtl( FIONREAD, &nBytes ) || nBytes < (DWORD)nHeadSize ) //检查到达有多少字节
   return;
  nRecCount = Receive( &phs, nHeadSize, MSG_PEEK );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR ) //连接已经关闭
  {
   OnClose(0);
   return;
  }
  if( nRecCount != nHeadSize )  //不够包头长度
   return;

  nPackSize = phs.m_PackSize;
  if( m_pRecDataBuf == NULL )
   m_pRecDataBuf = (BYTE*)malloc( nPackSize );
  else
   m_pRecDataBuf = (BYTE*)realloc( m_pRecDataBuf, nPackSize );
 }
 else
 {
  nPackSize = ((CPackHead*)m_pRecDataBuf)->m_PackSize;
  if( m_nPrevDataSize >= nPackSize )  //永远也不应该出现这种情况
  {
   m_nPrevDataSize = 0;
   return;
  }
 }
 nRecCount = Receive( m_pRecDataBuf + m_nPrevDataSize, nPackSize - m_nPrevDataSize );
 if( nRecCount == 0 || nRecCount == SOCKET_ERROR ) //连接已经关闭
 {
  OnClose( 0 );
  return;
 }
 m_nPrevDataSize += nRecCount;
 if( m_nPrevDataSize == nPackSize )
 {
//  if( s_pProcRespSock != NULL )  //如果本Socket处于子线程里,那么下面的响应函数如果位于别的线程,这就需要进行线程同步
//   s_pProcRespSock( this, m_pRecDataBuf, nPackSize );
  OnRecResponse( m_pRecDataBuf, nPackSize );
  m_nPrevDataSize = 0;
  free( m_pRecDataBuf );
  m_pRecDataBuf = NULL;
  if( IOCtl( FIONREAD, &nBytes ) && nBytes > 0 )
   OnReceive( 0 );
 }*/
}

void CAdmitSocket::OnClose(int nErrorCode)
{
 Close();
}

BOOL CAdmitSocket::Listen( int nPort )
{
 if( nPort == 0 )
  nPort = LISTENPORT1;
 if( m_hSocket == INVALID_SOCKET && !Create( nPort ) )
  return FALSE;
 return (m_bListen = CSocket::Listen( 0x7fffffff ));
}

void CAdmitSocket::OnAccept(int nErrorCode)
{
 CAdmitSocket* psockit = (CAdmitSocket*)this->GetRuntimeClass()->CreateObject();
 ASSERT( psockit != NULL );
 if( !Accept( *psockit ) )
  delete psockit;
 s_SockArray.Add( psockit );
 OnAcceptSocket( psockit );
 CSocket::OnAccept( nErrorCode ); 
}

void CAdmitSocket::Close()
{
// DWORD nBytes = 0;
// IOCtl( FIONREAD, &nBytes );

 

 CSocket::Close();
 int i, nCount = s_SockArray.GetSize();
 if( m_bListen )
 {
  for( i=0; i<nCount; i++ )
  {
   delete s_SockArray[i];
  }
  s_SockArray.RemoveAll();
 }
 else
 {
  for( i=0; i<nCount; i++ )
  {
   if( s_SockArray[i] == this )
   {
    OnSocketClose();
    s_SockArray.RemoveAt( i );
    delete this;
    break;
   }
  }
 }
}

BOOL CAdmitSocket::Connect( LPCTSTR lpszHostAddress, UINT nHostPort )
{
 if( m_hSocket == INVALID_SOCKET && !Create() )
  return false;
 if( nHostPort == 0 )
  nHostPort = LISTENPORT1;
 if( !CSocket::Connect( lpszHostAddress, nHostPort ) )
 {
  if( GetLastError() != WSAEWOULDBLOCK )
   return FALSE;
 }
 return TRUE;
}

BOOL CAdmitSocket::Send( WORD nPackFlag, const void* lpBuf, int nBufLen )
{
/* CPackHead  ph;
 ASSERT( nBufLen > 0 );
 ph.m_PackFlag  = nPackFlag;
 ph.m_PackSize  = sizeof(ph) + ((UINT)nBufLen);
 if( CSocket::Send( &ph, sizeof(ph) ) == SOCKET_ERROR )
  return FALSE;
 if( nBufLen > 0 )
  return (CSocket::Send( lpBuf, nBufLen ) != SOCKET_ERROR);
 return TRUE;
*/
 int nHeadSize = sizeof(CPackHead);
 CPackHead* pPackHead;
 BYTE* lpSendBuf = new BYTE[nHeadSize+nBufLen];
 pPackHead = (CPackHead*)lpSendBuf;
 pPackHead->m_PackFlag = nPackFlag;
 pPackHead->m_PackSize = (UINT)(nHeadSize + nBufLen);
 if( nBufLen > 0 )
  CopyMemory( lpSendBuf+nHeadSize, lpBuf, nBufLen );
 if( CSocket::Send( lpSendBuf, pPackHead->m_PackSize ) == SOCKET_ERROR )
 {
  delete [] lpSendBuf;
  return FALSE;
 }
 delete [] lpSendBuf;
 return TRUE;
}

0 0

相关博文

我的热门文章

img
取 消
img