📄 transfersocket_hawk.cpp
字号:
// TransferSocket_hawk.cpp : implementation file
//
#include "stdafx.h"
#include "TransferSocket_hawk.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTransferSocket_hawk
CTransferSocket_hawk::CTransferSocket_hawk()
{
m_nSendOffset=0;
m_bGetRecvSize=FALSE;
m_nRecvSizeOffset=0;
m_bGetRecvBeginTag=FALSE;
m_nRecvBeginTagOffset=0;
m_pRecvBuf=NULL;
}
CTransferSocket_hawk::~CTransferSocket_hawk()
{
Close();
}
// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CTransferSocket_hawk, CAsyncSocket)
//{{AFX_MSG_MAP(CTransferSocket_hawk)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
/////////////////////////////////////////////////////////////////////////////
// CTransferSocket_hawk member functions
BOOL CTransferSocket_hawk::Create(UINT nSocketPort,LPCTSTR lpszSocketAddress)
{
//总是"流"类型的SOCKET
return CAsyncSocket::Create(
nSocketPort,
SOCK_STREAM,
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
lpszSocketAddress);
}
BOOL CTransferSocket_hawk::TransferData(const void *pData,long size)
{
if (m_hSocket != INVALID_SOCKET)
{
//加入长度和"开始"标记
BYTE *buf=new BYTE [sizeof(long)+BEGIN_TAG_LENGTH+size];
memcpy(buf,&size,sizeof(long));
memcpy(buf+sizeof(long),BEGIN_TAG,BEGIN_TAG_LENGTH);
memcpy(buf+sizeof(long)+BEGIN_TAG_LENGTH,pData,size);
//如果数据队列为空,则提名FD_WRITE事件,以便执行OnSend来发送数据.
//如果队列非空,说明有数据正在发送.发送完后,由于队列又加入新数据,
//还会继续提名FD_WRITE,因此就不需要提名FD_WRITE.
if (!m_DataQueue.GetSize())
AsyncSelect();
m_DataQueue.Add(buf);
m_DataSizes.Add(sizeof(long)+BEGIN_TAG_LENGTH+size);
return TRUE;
}
else
return FALSE;
}
int CTransferSocket_hawk::GetQueueCount()
{
return m_DataQueue.GetSize();
}
void CTransferSocket_hawk::Clear()
{
//清除跟发送有关的类成员变量
while (m_DataQueue.GetSize())
{
delete [] m_DataQueue[0];
m_DataQueue.RemoveAt(0);
m_DataSizes.RemoveAt(0);
}
m_nSendOffset=0;
//清除跟接收有关的类成员变量
m_bGetRecvSize=FALSE;
m_nRecvSizeOffset=0;
m_bGetRecvBeginTag=FALSE;
m_nRecvBeginTagOffset=0;
if (m_pRecvBuf)
{
delete [] m_pRecvBuf;
m_pRecvBuf=NULL;
}
}
void CTransferSocket_hawk::Close()
{
Clear();
CAsyncSocket::Close();
}
void CTransferSocket_hawk::OnClose(int nErrorCode)
{
Close();
OnTransferClose(NORMAL);
CAsyncSocket::OnClose(nErrorCode);
}
void CTransferSocket_hawk::OnTransferClose(int reason,int nErrorCode)
{
}
void CTransferSocket_hawk::OnSend(int nErrorCode)
{
//之所以还要判断SOCKET句柄,是基于以下两个原因:
//1 如果一个SOCKET同时既发送数据,又接收数据,当出现发送(或接收)
// 错误后,即使在OnSend(或OnReceive)中关闭了SOCKET,理论上讲系统
// 也有可能调用OnReceive(或OnSend);
//2 曾经碰到过在服务器端正常关闭SOCKET后,客户端先调用OnClose,
// 然后又调用了OnSend,在Send时出错(一般是连接复位).如果在
// OnClose中关闭SOCKET,即使调用OnSend,也是什么都不做.
if (m_hSocket != INVALID_SOCKET)
{
//当连续发送大量数据时,程序可能会不响应用户的输入,
//因此需要加入消息循环代码.
MSG msg;
if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
//如果数据队列不为空,则发送数据
if (m_DataQueue.GetSize())
{
int nBufLen=min(4096,m_DataSizes[0]-m_nSendOffset);
int result=Send(m_DataQueue[0]+m_nSendOffset,nBufLen);
if (result == SOCKET_ERROR)
{
int err=GetLastError();
//如果不是阻塞引起的错误,则关闭SOCKET,
//并调用OnTransferClose.
//如果是阻塞引起的错误,系统会自己产生一次FD_WRITE事件,
//可以继续发送数据.
if (err != WSAEWOULDBLOCK)
{
Close();
OnTransferClose(SENDERR,err);
}
}
else
{
m_nSendOffset+=result;
//判断该数据块是否已传送完毕
if (m_nSendOffset == m_DataSizes[0])
{ //传送完毕,则删除该数据块
delete [] m_DataQueue[0];
m_DataQueue.RemoveAt(0);
m_DataSizes.RemoveAt(0);
m_nSendOffset=0;
//如果队列非空,提名FD_WRITE,准备传送下一个数据
if (m_DataQueue.GetSize())
AsyncSelect();
//调用虚函数OnOneDataSent,用户可根据需要重载该函数.
//注意:用户有可能在OnOneDataSent()的执行过程中,
// 调用TransferData()
OnOneDataSent();
}
else
//没传送完毕,则继续提名FD_WRITE
AsyncSelect();
}
}
}
CAsyncSocket::OnSend(nErrorCode);
}
void CTransferSocket_hawk::OnReceive(int nErrorCode)
{
//之所以还要判断SOCKET句柄,是基于以下两个原因:
//1 如果一个SOCKET同时既发送数据,又接收数据,当出现发送(或接收)
// 错误后,即使在OnSend(或OnReceive)中关闭了SOCKET,理论上讲系统
// 也有可能调用OnReceive(或OnSend);
//2 曾经碰到过在服务器端正常关闭SOCKET后,客户端先调用OnClose,
// 然后又调用了OnSend,在Send时出错(一般是连接复位),这样的话会
// 调用两次OnTansferClose().如果在OnClose中关闭SOCKET,即使
// 调用OnSend,也是什么都不做.
if (m_hSocket != INVALID_SOCKET)
{
//当连续接收大量数据时,程序可能会不响应用户的输入,
//因此需要加入消息循环代码.
MSG msg;
if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if (!m_bGetRecvSize)
{ //如果还没有接收完尺寸,继续接收尺寸数据
int result=Receive(
(BYTE *)&m_nRecvSize+m_nRecvSizeOffset,
sizeof(long)-m_nRecvSizeOffset);
if (result == SOCKET_ERROR)
{
int err=GetLastError();
//如果不是阻塞引起的错误,则调用OnTransferClose,
//并关闭连接.
if (err != WSAEWOULDBLOCK)
{
Close();
OnTransferClose(RECVERR,err);
}
}
else
{
m_nRecvSizeOffset+=result;
//如果已收到数据块尺寸,准备接收"起始"标记
if (m_nRecvSizeOffset == sizeof(long))
{
m_bGetRecvSize=TRUE;
m_nRecvSizeOffset=0;
}
}
}
else
{ //已经得到数据块尺寸
if (!m_bGetRecvBeginTag)
{ //如果没有接收完"起始"标记,继续接收
int result=Receive(
m_szRecvBeginTag+m_nRecvBeginTagOffset,
BEGIN_TAG_LENGTH-m_nRecvBeginTagOffset);
if (result == SOCKET_ERROR)
{
int err=GetLastError();
//如果不是阻塞引起的错误,则调用OnTransferClose,
//并关闭连接.
if (err != WSAEWOULDBLOCK)
{
Close();
OnTransferClose(RECVERR,err);
}
}
else
{
m_nRecvBeginTagOffset+=result;
if (m_nRecvBeginTagOffset == BEGIN_TAG_LENGTH)
{ //如果已收到"起始"标记,判断是否正确.
if (memcmp(m_szRecvBeginTag,BEGIN_TAG,BEGIN_TAG_LENGTH) == 0)
{
//如果"起始"标记正确,分配接收缓存区,
//准备接收数据正文
m_bGetRecvBeginTag=TRUE;
m_nRecvBeginTagOffset=0;
m_pRecvBuf=new BYTE [m_nRecvSize];
m_nRecvOffset=0;
}
else
{ //如果"起始"标记错误,调用OnTransferClose,
//并关闭连接
Close();
OnTransferClose(RECVBEGINTAGERR);
}
}
}
}
else
{ //数据块尺寸和"起始"标记都已正确接收,开始接收数据正文
int nBufLen=min(4096,m_nRecvSize-m_nRecvOffset);
int result=Receive(m_pRecvBuf+m_nRecvOffset,nBufLen);
if (result == SOCKET_ERROR)
{
int err=GetLastError();
//如果不是阻塞引起的错误,则调用OnTransferClose
if (err != WSAEWOULDBLOCK)
{
Close();
OnTransferClose(RECVERR,err);
}
}
else
{
m_nRecvOffset+=result;
//如果数据块接收完毕,则准备接收下一个数据块
if (m_nRecvOffset == m_nRecvSize)
{
//调用虚函数OnOneDataReceived.
//注意:用户在重载该函数时,需要把数据备份下来.
// 因为执行完该函数,收到的数据将被丢弃
OnOneDataReceived(m_pRecvBuf,m_nRecvSize);
m_bGetRecvSize=FALSE;
m_bGetRecvBeginTag=FALSE;
delete [] m_pRecvBuf;
m_pRecvBuf=NULL;
}
}
}
}
}
CAsyncSocket::OnReceive(nErrorCode);
}
void CTransferSocket_hawk::OnOneDataSent()
{
}
void CTransferSocket_hawk::OnOneDataReceived(void *pData,long size)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -