解决CSocket高数据传输问题

这个是自己项目中发现的问题,所以这个不一定适用于你的。

仅供参考。

头文件:

ESSocket.h

// ESSocket.h : header file
//
#ifndef ESSOCKET_H
#define ESSOCKET_H

#pragma once

#include <Winsock2.h>  // win32 socket stuff

#define WM_LTC_WINSOCK_MSG_RECEIVED WM_USER+001

/////////////////////////////////////////////////////////////////////////////
// CESSocket class - a replacement-class for CSocket of MFC
//
// CESSocket should not block on high data rate, as CSocket does. However,
// CESSocket is not a full replacement of CSocket.

class CESSocket
{
friend class CMessageTargetWnd;

public:
   CESSocket();
   virtual ~CESSocket();

protected:
   virtual void OnReceive(int nErrorCode);

public:
   bool Create();
   bool Connect(LPCTSTR lpszHostAddress, UINT nHostPort);
   int Send(const void* lpBuf, int nBufLen, int nFlags = 0);
   int Receive(void* lpBuf, int nBufLen, int nFlags = 0);
   void Close();
   int GetLastError();

private:
   CMessageTargetWnd *m_pWndMessageTarget;
   SOCKET m_sock;
   int m_nLastError;

   static int m_nInstanceCount;
};


//Helper class CMessageTargetWnd

class CMessageTargetWnd : public CWnd
{
public:
   CMessageTargetWnd(CESSocket*);

protected:
   LRESULT OnDataReceive(WPARAM, LPARAM);
   DECLARE_MESSAGE_MAP()

private:
   CESSocket *m_pESSocket;
};

#endif // ESSOCKET_H


ESSocket.cpp

// ESSocket.cpp
//
#ifndef WINVER
#if _MSC_VER <= 1200 // up to VC6.0
    #define WINVER 0x0400
#else
    #define WINVER 0x0501
#endif
#endif

#include <afxwin.h>
#include "ESSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// CESSocket class
//

int CESSocket::m_nInstanceCount = 0;

CESSocket::CESSocket()
{
   m_pWndMessageTarget = new CMessageTargetWnd(this);
   m_sock = 0;
   m_nLastError = 0;

   // keep track of #of instances; CESSocket is not designed to support multiple instances!
   m_nInstanceCount++;
   ASSERT(m_nInstanceCount == 1);
}


CESSocket::~CESSocket() 
{
   Close(); // just in case the application did not call Close()

   if (WSACleanup())
      TRACE(_T("WSACleanup() failed\n"));
      
   if (m_pWndMessageTarget)
   {
      if (::IsWindow(m_pWndMessageTarget->m_hWnd)) 
         VERIFY(m_pWndMessageTarget->DestroyWindow());

      delete m_pWndMessageTarget;
   }

   m_nInstanceCount--;
}


void CESSocket::OnReceive(int nErrorCode)
{
   ASSERT(false); // derived class does not provide an implementation for OnReceive()
   TRACE(_T("virtual OnReceive() called"));
}


bool CESSocket::Create()
{
   WSADATA WSAData;

   ASSERT(m_sock == 0); // call Create only once!
   m_nLastError = 0;

   if (m_nInstanceCount != 1)
   {
      ASSERT(false);
      return false; // this class does not support more than one instance
   }

   if (!::IsWindow(m_pWndMessageTarget->m_hWnd))
   {
      CWnd *pWndParent = CWnd::GetDesktopWindow();

      // This call may fail on Win98 / Unicode builds! use non- Unicode version in these cases
      m_pWndMessageTarget->CWnd::Create(NULL, _T("cessocket_message_sink"), WS_CHILD, 
                                        CRect(0, 0, 20, 20), pWndParent, 0);

      if (!::IsWindow(m_pWndMessageTarget->m_hWnd))
      {
         ASSERT(false);
         TRACE(_T("Creation or message- target window failed\n"));
         return false;
      }

      if (WSAStartup(MAKEWORD(1,1), &WSAData) == 0) 
      {
          m_sock = socket(PF_INET, SOCK_STREAM, 0);

          if (m_sock == INVALID_SOCKET)
          {
             m_nLastError = WSAGetLastError();
             m_sock = 0;
             WSACleanup();
             VERIFY(m_pWndMessageTarget->DestroyWindow());
             TRACE(_T("Socket creation failed\n"));
             return false;
          }
      }
      else
      {
         TRACE(_T("WSAStartup failed\n"));
         return false;
      }
   }
   else
   {
      ASSERT(m_sock != 0);
      ASSERT(false); // target window and socket already exists - Create should be called only once!
   }

   return true;
}


bool CESSocket::Connect(LPCTSTR lpszHostAddress, UINT nHostPort)
{
   #ifdef _UNICODE
   USES_CONVERSION; // for W2A macro
   #endif

   PHOSTENT phe;
   SOCKADDR_IN dest_sin;
   struct in_addr address;

   if (!m_pWndMessageTarget)
   {
      ASSERT(false);
      return false;
   }

   if (m_sock == 0)
   {
      // Did you miss to call Create()? Did you already close the socket?
      ASSERT(false);
      return false;
   }

   // Note: Once Close() is called, you cannot re-use the socket!
   // CESSocket class is neither designed to support multiple 
   // instances not to re-use once closed connections. You must
   // delete the current instance and create a new one for a 
   // re-connection or a connection to a different server.

   memset(&dest_sin, 0, sizeof dest_sin);
   dest_sin.sin_family = AF_INET;
   dest_sin.sin_port = htons(nHostPort); 

   if (_tcschr(lpszHostAddress, '.') == 0)
   {
      #ifdef _UNICODE
      phe = gethostbyname(W2A(lpszHostAddress));
      #else
      phe = gethostbyname(lpszHostAddress);
      #endif

      if (phe == NULL)
      {
         m_nLastError = WSAGetLastError();
         TRACE(_T("gethostbyname failed\n"));
         return false;
      } // if

      memcpy((char FAR *)&(dest_sin.sin_addr), phe->h_addr, phe->h_length);
   } // if
   else
   {
      #ifdef _UNICODE
      address.s_addr = inet_addr(W2A(lpszHostAddress));
      #else
      address.s_addr = inet_addr(lpszHostAddress);
      #endif

      dest_sin.sin_addr = address;
   }

   if (connect(m_sock, (LPSOCKADDR)&dest_sin, sizeof dest_sin))
   {
      m_nLastError = WSAGetLastError();
      TRACE(_T("Connection to server failed.\nCheck host-id and port# !\n"));
      return false;
   }
      
   if (WSAAsyncSelect(m_sock, *m_pWndMessageTarget, WM_LTC_WINSOCK_MSG_RECEIVED, FD_READ) > 0) 
   {
      m_nLastError = WSAGetLastError();
      TRACE(_T("WSAAsyncSelect failed\n"));
      return false;
   } // if

   TRACE(_T("Connection to server OK\n"));
   m_nLastError = 0;
   ASSERT(m_sock != 0);
   return true; // success
}


int CESSocket::Send(const void* lpBuf, int nBufLen, int nFlags)
{
   if (send(m_sock, (const char*)lpBuf, nBufLen, nFlags) == SOCKET_ERROR)
   {
      m_nLastError = WSAGetLastError();
      return false;
   }

   m_nLastError = 0;
   return true;
}


int CESSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
{
   int nBytes = 0;

   if ((nBytes = recv(m_sock, (char*)lpBuf, nBufLen, nFlags)) == SOCKET_ERROR)
   {
      m_nLastError = WSAGetLastError();
      return false;
   }

   m_nLastError = 0;
   return nBytes;
}


void CESSocket::Close()
{
   if (m_sock)
   {
      m_nLastError = 0;
      ASSERT(m_pWndMessageTarget);

      // stop receiving messages
      WSAAsyncSelect(m_sock, *m_pWndMessageTarget, 0, 0);

      if (closesocket(m_sock) == SOCKET_ERROR)
         m_nLastError = WSAGetLastError();

      m_sock = 0;
      TRACE(_T("Socket closed\n"));
   }
}


int CESSocket::GetLastError() 
{
   return m_nLastError;
}


/////////////////////////////////////////////////////////////////////////////
// CMessageTargetWnd class
//

CMessageTargetWnd::CMessageTargetWnd(CESSocket *pESSocket)
{
   m_pESSocket = pESSocket; 
}


LRESULT CMessageTargetWnd::OnDataReceive(WPARAM wParam, LPARAM lParam)
{
   m_pESSocket->OnReceive(HIWORD(lParam));
   return 0;
}

BEGIN_MESSAGE_MAP(CMessageTargetWnd, CWnd)
   ON_MESSAGE(WM_LTC_WINSOCK_MSG_RECEIVED, OnDataReceive)
END_MESSAGE_MAP()







posted @ 2014-04-08 16:51  水蒸蛋不好吃  阅读(218)  评论(0编辑  收藏  举报