18,356
社区成员
发帖
与我相关
我的任务
分享
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[MAX_PACKET_SIZE];
SOCKADDR_IN Address;
//用于发送数据时,分为两部分:高两个字节表示要发送的数据总长度,低两个字节表示已经发送的数据长度
//用于接收数据,表示接收到数据的总长度
UINT Length;
IoType Type;
} PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET hSocket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
//会话控制结构
typedef struct
{
PER_IO_OPERATION_DATA PerIoData;
PER_HANDLE_DATA PerHandleData;
SOCKADDR_IN HostAddr;
UINT64 LastTime;
PVOID ExtDataPtr;
Socket *ThisPtr; //所有者对象指针(这个结构所在类的对象指针)
Socket *SuperPtr; //管理者对象指针(管理ThisPtr对象的对象指针)
} SESSION, *LPSESSION;
RetCode UDPSocketImpl::PostRead(SESSION *Session)
{
INT addrLen = sizeof(SOCKADDR_IN);
LPPER_IO_OPERATION_DATA PerIoData = &(Session->PerIoData);
if (IsInit() == FALSE)
{
return RET_ENOINIT;
}
ZeroMemory(PerIoData, sizeof(PER_IO_OPERATION_DATA));
PerIoData->Type = IoReadFrom;
PerIoData->DataBuf.len = MAX_PACKET_SIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
DWORD dwFlags = 0;
if(WSARecvFrom(Handle(), &(PerIoData->DataBuf), 1, (LPDWORD)&(PerIoData->Length), &dwFlags,
(PSOCKADDR)(&(PerIoData->Address)), &addrLen, &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
LOGE(this->Logger(), "[%s] WSARecvFrom Filed with ErrorCode=%d", __FUNCTION__, WSAGetLastError());
return RET_ECALLAPI;
}
}
return RET_ESUC;
}
//工作线程
UINT WINAPI WorkerThread(LPVOID lParam)
{
HANDLE hCompletionPort = (HANDLE)lParam;
ASSERT(hCompletionPort != NULL);
CoInitialize(NULL);
while(bWorkState)
{
DWORD dwBytesTransferred = 0;
LPPER_HANDLE_DATA PerHandleData = NULL;
LPPER_IO_OPERATION_DATA PerIoData = NULL;
/************************************************************************
* 查询完成端口状态,如果有数据(发送或接受),则将数据填装在PerIOData *
* 中,然后将所对应的Socket句柄填装在PerhandleData,将数据大小填装在 *
* BytesTransFerred中 *
************************************************************************/
if (GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred,(PULONG_PTR)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE) == FALSE)
{
//错误处理,如果返回TRUE,则表示错误处理完成,FALSE表示错误没有得到处理,需要退出线程
if (!PerIoData || ErrorProcess(WSAGetLastError(), PerIoData))
{
continue;
}
//退出工作线程
break;
}
//退出特例检查处理
if(!PerIoData || ExceptProcess(PerIoData, dwBytesTransferred))
{
continue;
}
//分拣处理读写操作
switch(PerIoData->Type)
{
case IoRead:
{
ReadComplete(PerIoData, dwBytesTransferred);
break;
}
case IoReadFrom:
{
ReadFromComplete(PerIoData, dwBytesTransferred);
break;
}
case IoWrite:
{
WriteComplete(PerIoData, dwBytesTransferred);
break;
}
case IoWriteTo:
{
WriteToComplete(PerIoData, dwBytesTransferred);
break;
}
case IoAccept:
{
AcceptComplete(PerIoData, dwBytesTransferred);
break;
}
case IoDisConnect:
{
CloseComplete(PerIoData, dwBytesTransferred);
break;
}
case IoConnect:
{
ConnectComplete(PerIoData, dwBytesTransferred);
break;
}
default:break;
}
}
CoUninitialize();
return 1;
}
static inline VOID ReadFromComplete(LPPER_IO_OPERATION_DATA PerIoData, DWORD dwBytesTransferred)
{
//获得连接数据
LPSESSION Session = (LPSESSION)PerIoData;
//作用对象指针检查
ASSERT(Session->ThisPtr != NULL);
LOGW(Session->ThisPtr->Logger(), "[%s] PerIoData->Type=%d, dwBytesTransferred=%ld", __FUNCTION__, PerIoData->Type, dwBytesTransferred);
//处理数据
PacketProcess(PerIoData, dwBytesTransferred);
//继续投递读操作
if (((UDPSocketImpl*)(Session->ThisPtr))->PostRead(Session) != RET_ESUC)
{
CloseProcess(PerIoData);
return;
}
}
//错误处理
static inline BOOL ErrorProcess(DWORD dwErr, LPPER_IO_OPERATION_DATA PerIoData)
{
BOOL bRet = FALSE;
//如果是客户端异常断开,则删除所有对应的结构
/*****************************************************************************
* ERROR_NETNAME_DELETED 指定的网络名不再可用 *
* ERROR_INVALID_PARAMETER 参数不正确 *
* ERROR_UNEXP_NET_ERR 出现了意外的网络错误 *
* ERROR_CONNECTION_ABORTED 由本地系统终止网络连接 *
* ERROR_OPERATION_ABORTED 由于线程退出或应用程序请求,已放弃 I/O 操作 *
* ERROR_CONNECTION_REFUSED 连接被拒绝 *
* ERROR_PORT_UNREACHABLE 目标端口不可达(网卡发生丢包时产生的) *
* ERROR_NOACCESS 访问地址错误 *
******************************************************************************/
//
//如果IOCP环境已经退出,则不再处理后续错误,直接让工作线程返回 -- by yshen on 2014/02/01
//关闭客户端,需要将内存返回给内存池,并重用socket,所以必须通过DisconnectEx来关闭socket
//
if (bWorkState && HASH_GETBIT(hashbit, dwErr) > 0)
{
Socket *pSocket = ((LPSESSION)PerIoData)->ThisPtr;
ASSERT(pSocket != NULL);
LOGW(pSocket->Logger(), "entry [%s] type=%d, socket=%d, Err=%d", __FUNCTION__, PerIoData->Type, pSocket->Handle(), dwErr);
if (pSocket->SocketListener() != NULL)
{
pSocket->SocketListener()->OnError(pSocket, (SocketOption)PerIoData->Type, dwErr);
}
CloseProcess(PerIoData);
return TRUE;
}
return FALSE;
}
static inline BOOL ExceptProcess(LPPER_IO_OPERATION_DATA PerIoData, DWORD dwBytesTransferred)
{
// 客户端正常关闭时
if (bWorkState &&
dwBytesTransferred == 0 &&
PerIoData->Type != IoAccept &&
PerIoData->Type != IoDisConnect &&
PerIoData->Type != IoConnect)
{
CloseProcess(PerIoData);
return TRUE;
}
return FALSE;
}