#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "OverlapdIO.h"
#include <process.h>
#include <intrin.h> // 使用线程间包含原子锁的头文件
#pragma comment(lib,"ws2_32.lib")
LONG OverlapdIO::bTarget;
NetCallBack OverlapdIO::NetProc;
OverlapdIO::OverlapdIO()
{
m_sListen = 0;
m_sClient = 0;
wsaEvent = 0;
bTarget = FALSE;
}
OverlapdIO::~OverlapdIO()
{
WSACloseEvent(wsaEvent);
closesocket(m_sListen);
WSACleanup();
}
bool OverlapdIO::InitNet(NetCallBack func, UINT nSocketPOrt, LPCSTR lpszSocketAddr /*= ADDR_ANY*/)
{
if (!WinSockInit(nSocketPOrt, lpszSocketAddr))
{
printf("WinSockInit failed:%d\n", WSAGetLastError());
return false;
}
NetProc = func; // 初始化数据处理函数
wsaEvent = WSACreateEvent();
if (WSA_INVALID_EVENT == wsaEvent)
{
printf("WSACreateEvent failed:%d\n", WSAGetLastError());
return false;
}
// begin accept thread
_beginthreadex(0, 0, AcceptProc, this, 0, 0);
SOCKET tmpSock = 0;
SOCKADDR_IN tmpAddr;
int nLen = sizeof(SOCKADDR_IN);
while (true)
{
memset((void*)&tmpAddr, 0, nLen);
tmpSock = accept(m_sListen, (struct sockaddr*)&tmpAddr, &nLen);
if (INVALID_SOCKET != m_sClient)
{
while (InterlockedExchange(&bTarget, TRUE) == TRUE)// 获取原子锁
{
Sleep(0);//等待锁这段时间...你可以做其他事
}
memcpy(&m_cAddr, &tmpAddr, nLen);
m_sClient = tmpSock;
InterlockedExchange(&bTarget, FALSE);// 释放原子锁
WSASetEvent(wsaEvent);
}
}
return true;
}
/************************************************************************/
/* 进行消息发送的异步投递 */
/************************************************************************/
bool OverlapdIO::WSASendToClient(const SOCKET_OVERLAPD& sockOvlp, void* lparam)
{
DWORD dwRet = 0;
char* buf = (char*)lparam;
SOCKET_OVERLAPD sendOvlp = sockOvlp;
memcpy(sendOvlp.szMsg, buf, strlen(buf));
sendOvlp.Flags = 0;
if (SOCKET_ERROR == WSASend(sendOvlp.sock, &(sendOvlp.wsaBuf), 1, &(sendOvlp.dwSendBytes), sendOvlp.Flags, &(sendOvlp.overlap), NULL))
{
dwRet = WSAGetLastError();
if (dwRet != WSA_IO_PENDING)
{
printf("WSASend failed:%d\n", dwRet);
return false;
}
}
return true;
}
/************************************************************************/
/*初始化网络的一切操作 */
/************************************************************************/
bool OverlapdIO::WinSockInit(UINT nSocketPOrt, LPCSTR lpszSocketAddr /*= ADDR_ANY*/)
{
bool nRet = false;
do
{
WSADATA data = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &data))
break;
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
break;
m_sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (m_sListen == INVALID_SOCKET)
break;
SOCKADDR_IN addr = { AF_INET,htons(nSocketPOrt) };
if (lpszSocketAddr)
addr.sin_addr.S_un.S_addr = inet_addr(lpszSocketAddr);
if (SOCKET_ERROR == bind(m_sListen, (sockaddr*)&addr, sizeof(addr)))
break;
if (SOCKET_ERROR == listen(m_sListen, SOMAXCONN))
break;
nRet = true;
} while (false);
return nRet;
}
/************************************************************************/
/* 接收连接的线程,将接收到的连接进行判断并投递一个异步操作(WSARecv) */
/************************************************************************/
unsigned int __stdcall OverlapdIO::AcceptProc(void* lparam)
{
OverlapdIO* pThis = (OverlapdIO*)lparam;
WSAEVENT eventArry[1] = { 0 };
eventArry[0] = pThis->wsaEvent;
DWORD dwIndex = 0;
DWORD dwRet = 0;
LPSOCKET_OVERLAPD sockOvlp;
while (true)
{
while (true)
{
//等待连接的事件信号到来,最后一个参数为TRUE:将线程置于可警告的等待状态
//SleepEx()函数也可将线程设置为可警告的等待状态
dwIndex = WSAWaitForMultipleEvents(1, eventArry, FALSE, WSA_INFINITE, TRUE);
if (WSA_WAIT_FAILED == dwIndex) //failed
{
printf("WSAWaitForMultipleEvent failed:%d\n", WSAGetLastError());
continue;
}
if (WAIT_IO_COMPLETION != dwIndex) //is not incomplete
break;
}
WSAResetEvent(eventArry[dwIndex - WSA_WAIT_EVENT_0]); //reset event
// 在全局区申请内存,此处申请程序默认堆内存,所以注释
// sockOvlp = (LPSOCKET_OVERLAPD)GlobalAlloc(GPTR, sizeof(SOCKET_OVERLAPD));
// if (NULL == sockOvlp)
// {
// printf("GlobalAlloc() failed:%d\n", GetLastError());
// GlobalFree(sockOvlp);
// continue;
// }
// ZeroMemory((void*)&(sockOvlp->overlap), sizeof(WSAOVERLAPPED));
sockOvlp = (LPSOCKET_OVERLAPD)HeapAlloc(// 在程序的默认堆上申请内存
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SOCKET_OVERLAPD));
if (NULL == sockOvlp)
{
printf("HeapAlloc() failed:%d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, sockOvlp);
continue;
}
sockOvlp->wsaBuf.len = MAXSIZE;
sockOvlp->wsaBuf.buf = sockOvlp->szMsg;
sockOvlp->Flags = 0;
while (InterlockedExchange(&bTarget, TRUE) == TRUE) // 获取原子锁,保证m_sClient与m_cAddr值
{
Sleep(0);
}
sockOvlp->sock = pThis->m_sClient;
sockOvlp->addr = pThis->m_cAddr;
InterlockedExchange(&bTarget, FALSE);
if (SOCKET_ERROR == WSARecv(sockOvlp->sock, &(sockOvlp->wsaBuf), 1, &(sockOvlp->dwRecvdBytes),
&(sockOvlp->Flags), &(sockOvlp->overlap), (LPWSAOVERLAPPED_COMPLETION_ROUTINE)CompeletRoutine))
{
dwRet = WSAGetLastError();
if (WSA_IO_PENDING != dwRet) // WSA_IO_PENDING 重叠IO操作成功,等待稍后完成
{
HeapFree(GetProcessHeap(), 0, sockOvlp);
printf("WSARecv failed:%d\n", dwRet);
};
}
}
return 0;
}
/************************************************************************/
/* 完成例程,就相当于一个系统的回调函数 */
/************************************************************************/
void CALLBACK OverlapdIO::CompeletRoutine(DWORD dwError, DWORD dwBytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD dwFlags)
{
DWORD dwRet = 0;
LPSOCKET_OVERLAPD pOvl = (LPSOCKET_OVERLAPD)Overlapped;
if (dwError != 0 || dwBytesTransferred == 0)
{
if (dwError != 0)
printf("CompeletRoutine dwError:%d\n", dwError);
if (dwBytesTransferred == 0)
printf("[%s:%d]--->log off\n", inet_ntoa(pOvl->addr.sin_addr),htons(pOvl->addr.sin_port));
closesocket(pOvl->sock);
HeapFree(GetProcessHeap(), 0, pOvl); // 释放堆空间
//GlobalFree(pOvl);
return;
}
NetProc((void *)pOvl); // 处理函数(用于处理接收的数据)
ZeroMemory((void *)&(pOvl->overlap), sizeof(WSAOVERLAPPED));// 清空填0
pOvl->Flags = 0;
pOvl->wsaBuf.len = MAXSIZE;
ZeroMemory((void*)pOvl->szMsg, MAXSIZE);
pOvl->wsaBuf.buf = pOvl->szMsg;
if (SOCKET_ERROR == WSARecv(pOvl->sock, &(pOvl->wsaBuf), 1, &(pOvl->dwRecvdBytes),
&(pOvl->Flags), &(pOvl->overlap), (LPWSAOVERLAPPED_COMPLETION_ROUTINE)CompeletRoutine))
{
dwRet = WSAGetLastError();
if (WSA_IO_PENDING != dwRet) // 重叠IO操作成功,等待稍后完成
printf("WSARecv failed:%d\n", dwRet);
}
}