完成端口服务端数据发送不出去!

天地大美 2008-02-17 10:30:07
我用iocp封装了一个类,做的服务器端,提供文件下载。
我是在线程里调用 wsasend发送的。
在本地测试,服务端工作良好可以提供下载文件。但放到远程服务器上时,就不能下载文件,数据发不出去。
排除服务器电脑和带宽问题。
下面是我封装的IOCP类,哪位大哥指示一下,不胜感激。

IOCPS.H
/////////////////
#include "../template/listtemplate.h" //自定义的链表模板类
#include "../template/hashlist.h" //自定义的HASH链表模板类


////////////////完成端口封装类/////////////////////////

#define IOCP_MAXBUFSIZE (4096+256) //最大缓冲区长度4K
#define CONNECT_TIMEOUT 20 //连接后多久没有收到数据自动断开(单位:秒)


typedef enum _IO_OPERATION
{
IOInitialize=100, // The client just connected
IOReadCompleted, // Read completed
IOWriteCompleted, // 发送完成一个

}IO_OPERATION, *PIO_OPERATION;



static GUID g_GUIDAcceptEx = WSAID_ACCEPTEX;


extern void ShowMsg(LPCSTR msg);

class CIOCPS
{
public:
class CClientContext
{
public:
WSAOVERLAPPED ol; //overlapped用于来回传递的没用的东西

IO_OPERATION IoOperation; //IO操作标志
SOCKET sClient; //套接字句柄
WSABUF wsaBuf; //
char Buf[IOCP_MAXBUFSIZE];//发送数据缓冲区
public:
CClientContext(IO_OPERATION iooper=IOInitialize,SOCKET s=INVALID_SOCKET,DWORD len=IOCP_MAXBUFSIZE)
{
IoOperation=iooper;
wsaBuf.buf=Buf;
wsaBuf.len=len;
sClient=s;
memset(&ol,0,sizeof(WSAOVERLAPPED));//必须初始化,否则在调用ACCEPTEX时出现错误代码6的错误

}
public:
void SetOperation(IO_OPERATION iooper){IoOperation=iooper;}
IO_OPERATION GetOperation(){return IoOperation;}
BOOL AddData(char *buf,int len)
{
if(len>IOCP_MAXBUFSIZE)
return FALSE;
memcpy(Buf,buf,len);
wsaBuf.buf=Buf;
wsaBuf.len=len;
return TRUE;
}
};
/////////////////////////////////////////////////////
class CClientSocket
{
public:
CListTemplate<CClientContext> ClientBuf;
SOCKET sClient; //套接字句柄

public:
CClientSocket()
{
sClient=INVALID_SOCKET;
}
~CClientSocket()
{
ClientBuf.DistoryList();
}
public:
CClientContext *AllocBuffer(IO_OPERATION io_oper,SOCKET s,DWORD datalen=IOCP_MAXBUFSIZE)
{
CClientContext newnode(io_oper,s,datalen);
return ClientBuf.AddNode(&newnode);
}
CClientContext *SafeAllocBuffer(IO_OPERATION io_oper,SOCKET s,DWORD datalen=IOCP_MAXBUFSIZE)
{//安全分配内存,如果超出范围则返回空,调和用者应该等待数据处理完毕再调用送

if(ClientBuf.GetCount()>6)//如果当前有太多未处理IO包,则返回空,
return NULL;

CClientContext newnode(io_oper,s,datalen);
return ClientBuf.AddNode(&newnode);
}
void ReleaseBuffer(CClientContext *pBuf)
{
if(pBuf==NULL)return;
POSITION pos=ClientBuf.GetFirstPosition();
CClientContext *pNode=NULL;
for(;pos!=NULL;)
{
pNode=ClientBuf.GetAt(pos);
if(pNode==pBuf)
{
ClientBuf.DelNode(pos);
return;
}
ClientBuf.MoveNext(pos);
}
ShowMsg("ReleaseBuffer Error");
}

};
///////////////////////////////////////////////////////////////
public:
HANDLE m_hIOCP;//完成端口句柄
SOCKET m_hListenSocket;//监听套接字句柄
HANDLE m_hAcceptEvent;//有需要接受连接的请求通知事件
LPFN_ACCEPTEX lpAcceptEx;

CRITICAL_SECTION m_AcceptClientListSection;//
CListTemplate<CClientSocket> m_AcceptClientList; //已经接受连接并且未收到数据的套接字链表

CHashList<CClientSocket> m_ClientList; //客户端链表
CRITICAL_SECTION m_ClientListSection;//

public:
DWORD m_dwListenThreadID; //
BOOL m_bShutDown;

HANDLE m_hListenThreadHandle;
DWORD m_dwWorkerThreadCount;
HANDLE *m_pWorkerThreadHandleArray;
public:
CIOCPS();
virtual ~CIOCPS();
public:
static UINT TF_QueryIoStatusThread(LPVOID lp);//循环调用GetQueuedCompletionStatus获取当前IO状态的线程
static UINT TF_ListenThread(LPVOID lp);//监听线程,用于接受客户端的连接请求

protected:
virtual void AppendLog(CString msg)
{ }
virtual void NotifyOnAccept(SOCKET s)
{ }
virtual void NotifyOnDisconnect(SOCKET s)
{ }
virtual void NotifyOnReceive(SOCKET s,char *buf,DWORD len)
{ }
virtual void NotifyOnSendComplete(SOCKET s)
{ }
private:
BOOL InitWinsock();
BOOL PostAcceptEx();
void ProcessIOMessage(IO_OPERATION IoOperation,CClientContext *pContext,DWORD dwIoSize);
CString ErrorCode2Text(DWORD dw);
void LockAcceptList();
void UnlockAcceptList();
void DelSocketOnAcceptList(SOCKET s);
void LockClientList();
void UnlockClientList();

private:
void OnReadCompleted(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize);
void OnWrite(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize);
void OnWriteCompleted(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize);
public:
BOOL Startup(char *pListenIp,u_short uListenPort);
BOOL SendData(SOCKET s,char *buf,int len);
int SafeSendData(SOCKET s,char *buf,int len);

void ShutDown();
public:
void DisConnectClient(SOCKET s);
};

#endif // !defined(AFX_IOCPS_H__6F522E84_238B_4DC2_A27B_B415B99D3FA4__INCLUDED_)
...全文
453 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
zdleek 2008-02-19
  • 打赏
  • 举报
回复
既然你本地是可以正常工作的,那么问题应该不在软件代码
较大的可能是远程服务器的安全设置阻止了你的服务器正常工作
3m2u 2008-02-18
  • 打赏
  • 举报
回复
当你找不到问题的时候最好把一些相关信息都打印出来。
比如
if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING )
{
if(WSAGetLastError()!=WSAENOTSOCK)
{
// Remove Unnecessary disconnect messages in release mode..
if(WSAGetLastError()!=WSAECONNRESET&&WSAGetLastError()!=WSAECONNABORTED)
{
CString msg;
msg.Format("Error in SendData..: %s",ErrorCode2Text(WSAGetLastError()));
AppendLog(msg);
}
}
//其它情况应该把last error也打印出来
DisConnectClient(pClient-> sClient);
ShowMsg("SendData fail");

return -1;
}

另外得到完成通知后所有可能出错的情况也要处理,并且打印last error
zhoujianhei 2008-02-18
  • 打赏
  • 举报
回复
发送前,确认SOCKET是否有效。
ydlchina 2008-02-18
  • 打赏
  • 举报
回复
xuexi学习
天地大美 2008-02-18
  • 打赏
  • 举报
回复
哎,代码完全没有问题,是电信机房的端口问题,
captain_x 2008-02-18
  • 打赏
  • 举报
回复
6楼说的有道理
jourbin 2008-02-17
  • 打赏
  • 举报
回复
调试呗

这么长的代码,懒得看

至少也得自己先查查不行在哪里,总不能让人全部给你查吧

如果别人看代码就给你找出问题,而自己编写的人却不知道错在哪里
那说明你太懒,或者太烂
天地大美 2008-02-17
  • 打赏
  • 举报
回复
有点长,分了几部分贴完。
我在线程里直接调用 SendData发送文件,为什么在本地测试可以,放到机房的服务器电脑 上就不行了呢?
天地大美 2008-02-17
  • 打赏
  • 举报
回复

int CIOCPS::SendData(SOCKET s,char *buf,int len)
{
CClientSocket *pClient=m_ClientList.GetNodeData(s);


if(pClient==NULL)
{
AppendLog("SendData:if(pClient==NULL)");
return -1;
}

//为发送的数据分配一个缓冲区
CClientContext *pContext=pClient->AllocBuffer(IOWriteCompleted,s,len);
if(pContext==NULL)
{//需要等待分配到内存
ShowMsg("can't get buf");
return -2;
}
if(!pContext->AddData(buf,len))//将数据复制到新的缓冲区中
{//数据长度超出缓冲区最大空间
AppendLog("SendData:数据长度超出缓冲区最大空间");
pClient->ReleaseBuffer(pContext);
return 0;
}

ULONG ulFlags = 0;//MSG_PARTIAL;
DWORD dwSendNumBytes = 0;



int nRetVal = WSASend(pClient->sClient,
&pContext->wsaBuf,
1,
&dwSendNumBytes,
ulFlags,
&pContext->ol,
NULL);

if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING )
{
if(WSAGetLastError()!=WSAENOTSOCK)
{
// Remove Unnecessary disconnect messages in release mode..
if(WSAGetLastError()!=WSAECONNRESET&&WSAGetLastError()!=WSAECONNABORTED)
{
CString msg;
msg.Format("Error in SendData..: %s",ErrorCode2Text(WSAGetLastError()));
AppendLog(msg);
}
}
DisConnectClient(pClient->sClient);
ShowMsg("SendData fail");

return -1;
}

return len;
}
天地大美 2008-02-17
  • 打赏
  • 举报
回复

void CIOCPS::OnWrite(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize)
{

pContext->SetOperation(IOWriteCompleted);
ULONG ulFlags = 0;//MSG_PARTIAL;
DWORD dwSendNumBytes = 0;
int nRetVal = WSASend(pClient->sClient,
&pContext->wsaBuf,
1,
&dwSendNumBytes,
ulFlags,
&pContext->ol,
NULL);

if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING )
{
if(WSAGetLastError()!=WSAENOTSOCK)
{
// Remove Unnecessary disconnect messages in release mode..
if(WSAGetLastError()!=WSAECONNRESET&&WSAGetLastError()!=WSAECONNABORTED)
{
CString msg;
msg.Format("Error in SendData..: %s",ErrorCode2Text(WSAGetLastError()));
AppendLog(msg);
}
}
DisConnectClient(pClient->sClient);
ShowMsg("SendData fail");
}
}

void CIOCPS::OnWriteCompleted(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize)
{
if(pClient==NULL)return;
if(dwIoSize<=0)
{
AppendLog("OnWriteCompleted dwIoSize<=0!!!!! disconnect it.");
DisConnectClient(pClient->sClient);
return;
}
LockClientList();
NotifyOnSendComplete(pClient->sClient);
UnlockClientList();

pClient->ReleaseBuffer(pContext);//删除该节点
return;
}

void CIOCPS::OnReadCompleted(CClientSocket *pClient,CClientContext *pContext,DWORD dwIoSize)
{

if(pClient==NULL)
return;
if(dwIoSize<=0)
{
AppendLog("OnReadCompleted dwIoSize<=0!!!!!");
DisConnectClient(pClient->sClient);
return;
}

///-----------------------
LockClientList();
//接收数据用一个缓冲区就可以了,无须删除后重新分配
NotifyOnReceive(pClient->sClient,pContext->wsaBuf.buf,dwIoSize);
UnlockClientList();
///-----------------------


DWORD dwNumTrans=0;
ULONG ulFlags = 0;//MSG_PARTIAL;

pContext->wsaBuf.len=IOCP_MAXBUFSIZE;

UINT nRetVal = WSARecv(
pClient->sClient,
&pContext->wsaBuf,
1,
&dwNumTrans,
&ulFlags,
&pContext->ol,
NULL);
if(nRetVal == SOCKET_ERROR &&WSAGetLastError() != WSA_IO_PENDING)
{
if(WSAGetLastError()!=WSAENOTSOCK)
{
// Remove Unnecessary disconnect messages in release mode..
if(WSAGetLastError()!=WSAECONNRESET&&
WSAGetLastError()!=WSAECONNABORTED)
{
CString msg;
msg.Format("Disconnect in Onread Possible Socket Error: %s",ErrorCode2Text(WSAGetLastError()));
AppendLog(msg);
}
}

DisConnectClient(pClient->sClient);
}
}
void CIOCPS::ProcessIOMessage(IO_OPERATION IoOperation,CClientContext *pContext,DWORD dwIoSize)
{
if(pContext==NULL)return;

DWORD nResult;
HANDLE hResult;
CClientSocket *pClientContext=NULL;
CClientContext *pNewContext=NULL;

switch(IoOperation)
{
case IOInitialize: // The client just connected
{
CClientSocket *pClient=NULL;
POSITION pos=m_AcceptClientList.GetFirstPosition();
for(;pos!=NULL;)
{
pClient=m_AcceptClientList.GetAt(pos);
if(pClient==NULL)
break;
if(pClient->sClient==pContext->sClient)
break;
m_AcceptClientList.MoveNext(pos);
}
if(pClient==NULL)
{
return;
}
if(pClient->sClient!=pContext->sClient)
{
return;
}
SOCKET newsocket=pContext->sClient;

if(dwIoSize<=0)
{
closesocket(newsocket);
DelSocketOnAcceptList(newsocket);
break;
}
nResult = setsockopt(
newsocket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char *)&m_hListenSocket,
sizeof(m_hListenSocket)
);
if(SOCKET_ERROR == nResult)
{
AppendLog("IOInitialize SO_UPDATE_ACCEPT_CONTEXT failed to update accept socket");
closesocket(newsocket);
DelSocketOnAcceptList(newsocket);
break;
}

hResult = CreateIoCompletionPort(
(HANDLE)newsocket,
m_hIOCP,
newsocket,
0
);
if (NULL == hResult)
{
AppendLog("IOInitialize CreateIoCompletionPort() failed");
closesocket(newsocket);
DelSocketOnAcceptList(newsocket);
break;
}


LockAcceptList();

LockClientList();


CClientSocket NewClient;
//{{init obj

NewClient.sClient=pClient->sClient;

//}}


pClientContext=m_ClientList.AddNode(pClient->sClient,&NewClient);//将该连接添加到正常连接表
pNewContext=pClientContext->AllocBuffer(IOReadCompleted,newsocket,dwIoSize);

pNewContext->wsaBuf.buf=pNewContext->Buf;
memcpy(pNewContext->Buf,pContext->Buf,dwIoSize);



UnlockClientList();

pClient->ReleaseBuffer(pContext);
DelSocketOnAcceptList(pClient->sClient);
UnlockAcceptList();


PostQueuedCompletionStatus(
m_hIOCP,
dwIoSize,
(DWORD)newsocket,
&pNewContext->ol);


//--------------------------------------------
NotifyOnAccept(newsocket);
//--------------------------------------------

}
break;
case IOReadCompleted: // Read completed
{
CClientSocket *pClient=m_ClientList.GetNodeData(pContext->sClient);
if(pClient==NULL)
{//error
AppendLog("m_ClientList.GetNodeData(pContext->sClient); ERROR on ProcessIoMessage 1 ");
return;
}
OnReadCompleted(pClient,pContext,dwIoSize);
}
break;

/*
case IOWrite:
{
CClientSocket *pClient=m_ClientList.GetNodeData(pContext->sClient);
if(pClient==NULL)
{//error
AppendLog("m_ClientList.GetNodeData(pContext->sClient); ERROR on ProcessIoMessage 2 ");
return;
}
OnWrite(pClient,pContext,dwIoSize);
}
break;
//*/
case IOWriteCompleted: // Write Completed.
{
CClientSocket *pClient=m_ClientList.GetNodeData(pContext->sClient);
if(pClient==NULL)
{//error
AppendLog("m_ClientList.GetNodeData(pContext->sClient); ERROR on ProcessIoMessage 2 ");
return;
}
OnWriteCompleted(pClient,pContext,dwIoSize);
}
break;

default:
{
ShowMsg("unknown IoOperation");
if(dwIoSize<=0&&pContext!=NULL)
{
closesocket(pContext->sClient);
if(!m_ClientList.DelNode(pContext->sClient))
{//客户链表中没有,有可能是待接受的链表中
DelSocketOnAcceptList(pContext->sClient);
}
break;
}
}
break;
}
}
天地大美 2008-02-17
  • 打赏
  • 举报
回复

BOOL CIOCPS::Startup(char *pListenIp,u_short uListenPort)
{

m_hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);//创建一个完成端口
if(m_hIOCP==NULL)
{
AppendLog("创建完成端口句柄失败!");
return FALSE;
}

SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);//获取系统CPU数目,
m_dwWorkerThreadCount=SysInfo.dwNumberOfProcessors*2;

m_pWorkerThreadHandleArray=new HANDLE[m_dwWorkerThreadCount];

for (int i=0; i<(int)m_dwWorkerThreadCount; i++)//创建CPU数目*2个线程
{
m_pWorkerThreadHandleArray[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CIOCPS::TF_QueryIoStatusThread, (LPVOID)this, 0, NULL);
}//end of for

if(!InitWinsock())//初始化套接字
{//
//
//给完成端口线程发送消息,指示线程退出。
//
PostQueuedCompletionStatus(m_hIOCP, 0, NULL, NULL);
CloseHandle(m_hIOCP);
AppendLog("套接字初始化失败");
return FALSE;
}


//绑字并监听套接字
SOCKADDR_IN InternetAddr;
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = inet_addr(pListenIp);
InternetAddr.sin_port = htons(uListenPort);
if(SOCKET_ERROR ==bind(m_hListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)))
{
WSACleanup();
closesocket(m_hListenSocket);
AppendLog("绑定套接字失败!");
return FALSE;
}
if (SOCKET_ERROR == listen(m_hListenSocket, 20))
{
WSACleanup();
closesocket(m_hListenSocket);
AppendLog("监听套接字失败!");
return FALSE;
}

m_hAcceptEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//初始化为无信号
//将事件对象句柄和FD_ACCEPT关联
WSAEventSelect(m_hListenSocket, m_hAcceptEvent, FD_ACCEPT);

if(!PostAcceptEx())
{
WSACleanup();
closesocket(m_hListenSocket);
AppendLog("发出10个AcceptEx调用。失败!");
return FALSE;
}
m_hListenThreadHandle=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)TF_ListenThread,
(LPVOID)this,0,&m_dwListenThreadID);

if(m_hListenThreadHandle==NULL)
{
AppendLog("建立LISTEN线程失败!");
WSACleanup();
closesocket(m_hListenSocket);
return FALSE;
}

CString str;str.Format("IOCPServer startup successful! ServerIP:%s,ListenPort:%d.",pListenIp,uListenPort);
AppendLog(str);

return TRUE;
}
void CIOCPS::LockAcceptList()
{
EnterCriticalSection(&m_AcceptClientListSection);
}
void CIOCPS::UnlockAcceptList()
{
LeaveCriticalSection(&m_AcceptClientListSection);
}
void CIOCPS::LockClientList()
{
EnterCriticalSection(&m_ClientListSection);
}
void CIOCPS::UnlockClientList()
{
LeaveCriticalSection(&m_ClientListSection);
}
BOOL CIOCPS::PostAcceptEx()
//连续发出10个AcceptEx调用。
{
int nZero = 0;
SOCKET NewSocket=0;
DWORD dwBytes=0;
BOOL bSuccess;
CClientSocket WillAcceptClient;
CClientSocket *pWillAcceptClient;
CClientContext *pContext;
for(int i=0;i<10;i++)
{
NewSocket= WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, \
NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == NewSocket)
{
AppendLog("WSASocket failed! in PostAcceptEx");
return FALSE;
}


WillAcceptClient.sClient=NewSocket;
pWillAcceptClient=m_AcceptClientList.AddNode(&WillAcceptClient);

pContext=pWillAcceptClient->AllocBuffer(IOInitialize,NewSocket,IOCP_MAXBUFSIZE);


if(pWillAcceptClient==NULL)
{//
AppendLog("Add new socket to AccpetList Fail!");
return FALSE;
}



bSuccess = lpAcceptEx(
m_hListenSocket,
pContext->sClient,
pContext->Buf,
pContext->wsaBuf.len - ((sizeof(SOCKADDR_IN) + 16) * 2),
sizeof(SOCKADDR_IN) + 16,
sizeof(SOCKADDR_IN) + 16,
&dwBytes,
&(pContext->ol));

if (FALSE == bSuccess)
{
int nResult = WSAGetLastError();
if (nResult != ERROR_IO_PENDING)
{
CString str;str.Format("AcceptEx() failed ! [ %d ]",GetLastError());
AppendLog(str);
closesocket(NewSocket);
return FALSE;
}
}
}

return TRUE;
}//end of PostAccetEx()
void CIOCPS::DelSocketOnAcceptList(SOCKET s)
{

POSITION pos;
pos=m_AcceptClientList.GetFirstPosition();
if(pos==NULL)
{
return;
}
CClientSocket *pClient;
for(;pos!=NULL;)
{
pClient=m_AcceptClientList.GetAt(pos);
if(pClient==NULL)
{ break;}
if(pClient->sClient==s)
{
m_AcceptClientList.DelNode(pos);
break;
}
m_AcceptClientList.MoveNext(pos);
}
}

void CIOCPS::DisConnectClient(SOCKET s)
{
//////////////////////////////////////////

NotifyOnDisconnect(s);

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


closesocket(s);

LockClientList();
LockAcceptList();
if(!m_ClientList.DelNode(s))
{//客户链表中没有,有可能是待接受的链表中
DelSocketOnAcceptList(s);
}
else
{
CString str;
str.Format("DisConnectClient socket:[ %d ] closed!",s);
AppendLog(str);
}
UnlockClientList();
UnlockAcceptList();
}
天地大美 2008-02-17
  • 打赏
  • 举报
回复

UINT CIOCPS::TF_QueryIoStatusThread(LPVOID lp)//循环调用GetQueuedCompletionStatus获取当前IO状态的线程
{
CIOCPS* pThis = (CIOCPS*)lp;
if(pThis==NULL)
return 3;

DWORD dwIoSize;
CClientSocket *pClient;
BOOL bError=FALSE;
HANDLE hCompletionPort = pThis->m_hIOCP;
LPOVERLAPPED lpOverlapped;
DWORD CompletionKey;
BOOL bIORet=FALSE;
for(;;)
{
lpOverlapped=NULL;
pClient=NULL;
// Get a completed IO request.
bIORet=GetQueuedCompletionStatus(
hCompletionPort,
&dwIoSize,
(LPDWORD) &CompletionKey,
&lpOverlapped,
INFINITE);

// If Something whent wrong..
if (!bIORet)
{
DWORD dwIOError = GetLastError();
if(dwIOError != WAIT_TIMEOUT) // It was not an Time out event we wait for ever (INFINITE)
{
if (CompletionKey!=0)
{
/*
* ERROR_NETNAME_DELETED Happens when the communication socket
* is cancelled and you have pendling WSASend/WSARead that are not finished.
* Then the Pendling I/O (WSASend/WSARead etc..) is cancelled and we return with
* ERROR_NETNAME_DELETED..
*/
CClientContext *pContext=(CClientContext*)lpOverlapped;
if(dwIOError==ERROR_NETNAME_DELETED)
{
CClientContext *pContext=(CClientContext*)lpOverlapped;
if(pContext->sClient!=pThis->m_hListenSocket)
pThis->DisConnectClient(pContext->sClient);
}
else
{
if(pContext->GetOperation()!=IOWriteCompleted)
{ // Should not get here if we do: disconnect the client and cleanup & report.

CString str;
str.Format("ERR:%d---%d",dwIOError,pContext->GetOperation());
pThis->AppendLog(str);
pThis->AppendLog(pThis->ErrorCode2Text(dwIOError));


pThis->DisConnectClient(CompletionKey);
}
else// if(pContext->GetOperation()==IOWriteCompleted)
{//数据发送超时,可能是客户端断线或者网络不好
pThis->AppendLog("数据发送超时,可能是客户端断线或者网络不好");

}
}

// Clear the buffer if returned.
continue;
}
// We shall never come here
// anyway this was an error and we should exit the worker thread

pThis->AppendLog(pThis->ErrorCode2Text(dwIOError));
pThis->AppendLog("TF_QueryIoStatusThread KILLED BECAUSE OF ERROR IN GetQueuedCompletionStatus");
break;
}
}

if(bIORet && lpOverlapped && CompletionKey)
{
CClientContext *pContext=(CClientContext*)lpOverlapped;


pThis->ProcessIOMessage(pContext->GetOperation(),pContext, dwIoSize);
}

if(lpOverlapped==NULL&&
CompletionKey==NULL&&
pThis->m_bShutDown)
{
return 0;
}
}
return 0;
}

UINT CIOCPS::TF_ListenThread(LPVOID lp)//监听线程,用于接受客户端的连接请求
{
CIOCPS *pThis=(CIOCPS*)lp;
if(pThis==NULL)
return 3;

int nOptval;
int nOptlen;
int nResult;
DWORD dwResult;
CClientSocket *pClient;

for(;;)
{
if(pThis->m_bShutDown)
{
return 0;
}
dwResult = WaitForSingleObject(pThis->m_hAcceptEvent,10000);
if (dwResult== WAIT_FAILED )
{
PostQueuedCompletionStatus(pThis->m_hIOCP, 0, NULL, NULL);
pThis->AppendLog("WaitForSingleObject() failed");
return 1;
}

if(dwResult ==WAIT_TIMEOUT)
{
POSITION pos=pThis->m_AcceptClientList.GetFirstPosition();
POSITION pos2;
for(;pos!=NULL;)
{
pClient=pThis->m_AcceptClientList.GetAt(pos);
if(pClient==NULL)break;

pThis->LockAcceptList();

nOptlen = sizeof(nOptval);
nResult = getsockopt(
pClient->sClient,
SOL_SOCKET,
SO_CONNECT_TIME,
(char*)&nOptval,
&nOptlen
);
if (SOCKET_ERROR == nResult)
{
pThis->AppendLog("SO_CONNECT_TIME failed:");
closesocket(pClient->sClient);
pos2=pos;
pThis->UnlockAcceptList();
pThis->m_AcceptClientList.MoveNext(pos);
pThis->m_AcceptClientList.DelNode(pos2);
continue;
}
if ((nOptval!=0xFFFFFFFF) && (nOptval>CONNECT_TIMEOUT))
{
closesocket(pClient->sClient);
pos2=pos;
pThis->UnlockAcceptList();
pThis->m_AcceptClientList.MoveNext(pos);
pThis->m_AcceptClientList.DelNode(pos2);
pThis->AppendLog("Connected! But not received data.time out! Auto disconnect it!");
continue;
}

pThis->UnlockAcceptList();
pThis->m_AcceptClientList.MoveNext(pos);
}
}
else
{
if (pThis->PostAcceptEx()==FALSE)
{
PostQueuedCompletionStatus(pThis->m_hIOCP, 0, NULL, NULL);
return 2;
}
}
}
return 0;
}


CIOCPS::CIOCPS()
{
InitializeCriticalSection(&m_AcceptClientListSection);//
InitializeCriticalSection(&m_ClientListSection);//
m_dwListenThreadID=0;
m_bShutDown=FALSE;
m_pWorkerThreadHandleArray=NULL;
m_dwWorkerThreadCount=0;

}

CIOCPS::~CIOCPS()
{

ShutDown();
DeleteCriticalSection(&m_AcceptClientListSection);
DeleteCriticalSection(&m_ClientListSection);
}
BOOL CIOCPS::InitWinsock()
/*++

函数描述:
初始化Winsock,创建一个监听套接字,获取AcceptEx函数指针,为监听套接字分配一个单句柄
数据,并将监听套接字与完成端口hCOP关联。
--*/
{
WSADATA wsd;
int nResult = WSAStartup(MAKEWORD(2,2), &wsd);
if (0 != nResult)
{
AppendLog("WSAStartup() failed");
return FALSE;
}
if ( LOBYTE( wsd.wVersion ) != 2 ||HIBYTE( wsd.wVersion ) != 2 )
{
WSACleanup( );
AppendLog("操作系统无对应SOCKET版本支持!");
return FALSE;
}




//创建一个流式异步模式的套接字
m_hListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP,NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == m_hListenSocket)
{
AppendLog("创建套接字失败!");
WSACleanup();
return FALSE;
}


DWORD dwResult;

/*
有关AcceptEx()的最后一个注意事项:要实现这些API,并不需要其它提供商提供的Winsock2实现。这一点对微软特有的其它API也同样适用,比如TransmitFile()和GetAcceptExSockAddrs(),以及其它可能会被加入到新版Windows的API. 在Windows NT和2000上,这些API是在微软的底层提供者DLL(mswsock.dll)中实现的,可通过与mswsock.lib编译连接进行调用,或者通过WSAIoctl() (选项参数为SIO_GET_EXTENSION_FUNCTION_POINTER)动态获得函数的指针。
如果在没有事先获得函数指针的情况下直接调用函数(也就是说,编译时静态连接mswsock.lib,在程序中直接调用函数),那么性能将很受影响。因为AcceptEx()被置于Winsock2架构之外,每次调用时它都被迫通过WSAIoctl()取得函数指针。要避免这种性能损失,需要使用这些API的应用程序应该通过调用WSAIoctl()直接从底层的提供者那里取得函数的指针。
*/
//获取微软SOCKET扩展函数指针
//
nResult = WSAIoctl(
m_hListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&g_GUIDAcceptEx,
sizeof(g_GUIDAcceptEx),
&lpAcceptEx,
sizeof(lpAcceptEx),
&dwResult,
NULL,
NULL
);

if (SOCKET_ERROR == nResult)
{
AppendLog("获取AcceptEx函数地址失败!");
closesocket(m_hListenSocket);
WSACleanup();

return FALSE;
}



//
//将监听套接字gm_hListenSocket和已经建立的完成端口关联起来
//
if(CreateIoCompletionPort((HANDLE)m_hListenSocket,m_hIOCP,m_hListenSocket,0)==NULL)
{
closesocket(m_hListenSocket);
WSACleanup();
AppendLog("将套接字关联到完成端口的时候失败!");
return FALSE;
}

return TRUE;
}//end of InitWinsock()
void CIOCPS::ShutDown()
{

m_AcceptClientList.DistoryList();
m_bShutDown=TRUE;
PostQueuedCompletionStatus(m_hIOCP,0,0,NULL);//通知线程退出
PostQueuedCompletionStatus(m_hIOCP,0,0,NULL);//通知线程退出
PostQueuedCompletionStatus(m_hIOCP,0,0,NULL);//通知线程退出
if(m_pWorkerThreadHandleArray!=NULL)
{
for(DWORD i=0;i<m_dwWorkerThreadCount;i++)
{
TerminateThread(m_pWorkerThreadHandleArray[i],0);
CloseHandle(m_pWorkerThreadHandleArray[i]);
}
delete []m_pWorkerThreadHandleArray;
m_pWorkerThreadHandleArray=NULL;
}
TerminateThread(m_hListenThreadHandle,0);
CloseHandle(m_hListenThreadHandle);

}

18,363

社区成员

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

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