////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2000-2001 Softelf Inc. All rights reserved.
////////////////////////////////////////////////////////////////////////////////
//
// Author : Telan
// Date : 2000-10-04
// Purpose : Encapsulate winsock2 functions to make it more easily used
// History :
// 1.0 : 2000-03-10 - First Edition of this source code ( called:FE_SOCKET )
// 2.0 : 2000-06-25 - Second Edition ( name changed to TE_SOCKET )
// - Add Error Control
// 3.0 : 2000-09-21 - Third Edition ( name changed to TE_SOCKET )
// - Change the errors' process mechanism
// - Add BufSocket Model
// - Add TE_ConnectEx(...)
// - Add TE_BSocketGetData(...) for specail usage
// 3.1 : 2000-10-04 - Add TE_AcceptEx(...)
// - Add TE_GetIP(...) to fix NT DNS resolve cache problem
// - Modify TE_ConnectEx
// - Fix several bugs in NetEvent process
//
// Mailto :
[email protected] ( Bugs' Report or Comments )
// Notes : This source code may be used in any form in any way you desire. It is
// provided "as is" without express or implied warranty. Use it at your own
// risk! The author accepts no liability for any damage/loss of business
// that this product may cause.
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TE_Socket.h"
//需要ws2_32.lib库
#pragma comment(lib,"ws2_32.lib")
//错误代号
static __declspec(thread) int _iThreadedErrorNo = 0;
// 辅助函数
//获取最近一次操作的错误代码
int TE_GetLastError()
{
return (_iThreadedErrorNo);
}
//设置错误代码
void TE_SetLastError(int iErrorCode)
{
_iThreadedErrorNo = iErrorCode;
}
/////////////////////////////////////////////////////////////////////////
// Winsock2 函数
/////////////////////////////////////////////////////////////////////////
//初始化Winsock2动态连接库
int TE_InitLibrary()
{
WSADATA WSD;
WORD wVersionRequired = MAKEWORD( TE_SOCKET_MAJOR_VERSION,TE_SOCKET_MINOR_VERSION );
ZeroMemory(&WSD,sizeof(WSADATA));
int nErrorNo = WSAStartup(wVersionRequired, &WSD);
if ( SOCKET_SUCCESS != nErrorNo )
{
TE_SetLastError( nErrorNo );
return ( SOCKET_ERROR );
}
if ( LOBYTE( WSD.wVersion ) != TE_SOCKET_MINOR_VERSION ||
HIBYTE( WSD.wVersion ) != TE_SOCKET_MAJOR_VERSION )
{
WSACleanup( );
TE_SetLastError( WSAVERNOTSUPPORTED );
return (SOCKET_ERROR);
}
//成功初始化
return (SOCKET_SUCCESS);
}
//释放Winsock2动态连接库
void TE_CleanupLibrary(void)
{
WSACleanup();
}
//设置套接字属性
int TE_SetSocketOption(SOCKET hSocket)
{
int iActivate = 1;
//允许地址重用
if (setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) &iActivate,sizeof(iActivate)) == SOCKET_ERROR )
{
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
// 如果支持,设置KEEPALIVE属性 (这样做会带来其他不良后果)
//setsockopt(hSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *) &iActivate,sizeof(iActivate));
return (SOCKET_SUCCESS);
}
//创建具有重叠IO能力的套接字
SOCKET TE_CreateSocket(int iAddressFamily /*= AF_INET*/, int iType/*= SOCK_STREAM*/,int iProtocol/*= 0*/)
{
SOCKET hSocket = WSASocket(iAddressFamily, iType, iProtocol, NULL,0,WSA_FLAG_OVERLAPPED);
if ( hSocket == INVALID_SOCKET )
{
TE_SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
//设置套接字选项
if ( SOCKET_ERROR == TE_SetSocketOption(hSocket) ) //设置属性失败
{
TE_CloseSocket(hSocket, TRUE);
return (INVALID_SOCKET);
}
return (hSocket);
}
//关闭套接字
void TE_CloseSocket(SOCKET hSocket, BOOL bHardClose)
{
// 不需要捕获错误
if (!bHardClose) // 优雅关闭 Graceful close
{
// 不再发送数据,对于TCP套接字,在所有的数据都发送完毕之后,
// 将发送一个 FIN ,通知接收方所有数据已经发送完毕。
shutdown(hSocket, SD_SEND);
// 接收缓冲区有可能还有未接收的数据,在关闭套接字之前应该先
// 读取残留的数据。
int iRecvResult;
HANDLE hSocketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
char szBuffer[256];
do
{
if (hSocketEvent != NULL)
{
//注册网络事件
WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, FD_READ | FD_CLOSE);
WSAWaitForMultipleEvents(1, &hSocketEvent, TRUE,TE_SHUTDOWN_RECV_TIMEOUT, TRUE);
//清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, 0);
}
ZeroMemory(szBuffer,256);
iRecvResult = TE_RecvLL(hSocket, szBuffer, sizeof(szBuffer));
} while (iRecvResult > 0);
if (hSocketEvent != NULL)
CloseHandle(hSocketEvent);
//不再允许接收和发送
shutdown(hSocket, SD_BOTH);
}
// 关闭套接字
closesocket(hSocket);
}
// 一次性接收数据(重叠IO)
int TE_RecvLL(SOCKET hSocket, char *pszBuffer, int iBufferSize)
{
DWORD dwRtxBytes = 0,
dwRtxFlags = 0;
WSABUF WSABuff;
//清空缓冲
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = iBufferSize;
WSABuff.buf = pszBuffer;
return ((WSARecv(hSocket, &WSABuff, 1, &dwRtxBytes, &dwRtxFlags,NULL, NULL) == SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
}
// 接收数据(阻塞直至收到数据为止)
int TE_RecvData(SOCKET hSocket, char *pszBuffer, int iBufferSize, DWORD dwTimeout)
{
HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hReadEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return ( SOCKET_ERROR );
}
int iRecvBytes = 0;
DWORD dwWaitResult ;
for (;;)
{
// 注册FD_READ | FD_CLOSE 事件
// (因为可能在等待FD_READ事件中,对方关闭套接字,所以要关注FD_CLOSE)
if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
// 等等FD_READ | FD_CLOSE事件的发生
dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, TRUE,dwTimeout, TRUE);
if (dwWaitResult != WSA_WAIT_EVENT_0)
{
// 清除事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent) == SOCKET_ERROR)
{
// 清除事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//判断发生了什么事件 FD_READ 或 FD_CLOSE
if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
( NetEvent.lNetworkEvents == FD_READ &&
NetEvent.iErrorCode[FD_READ_BIT] !=0 ) ) // 发生错误
{
// 清除事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError(WSAGetLastError() );
return (SOCKET_ERROR);
}
////////////////////////////////////////////////////////////////
// 清除事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
// 接收数据
if ((iRecvBytes = TE_RecvLL(hSocket, pszBuffer, iBufferSize)) >= 0)
break; // 跳出循环
int iErrorCode = -iRecvBytes;
if ( iErrorCode != WSAEWOULDBLOCK ) //太多的未完成重叠操作
{
CloseHandle(hReadEvent);
TE_SetLastError( iErrorCode );
return (SOCKET_ERROR);
}
//阻塞住了
////////////////////////////////////////////////////////////////////////
// 如果发生阻塞,就等待一定时间后重试,以免CPU轮询浪费时间
////////////////////////////////////////////////////////////////////////
Sleep(TE_BLOCKED_SNDRCV_SLEEP);
}
CloseHandle(hReadEvent);
return (iRecvBytes);
}
// 接收数据直至达到规定的长度(缓冲区满)或超时或没有数据可读取时
int TE_Recv(SOCKET hSocket, char *pszBuffer, int iBufferSize, DWORD dwTimeout)
{
int iRtxBytes = 0;
int iRtxCurrent = 0;
while (iRtxBytes < iBufferSize)
{
iRtxCurrent = TE_RecvData(hSocket, (pszBuffer + iRtxBytes),(iBufferSize - iRtxBytes), dwTimeout);
if (iRtxCurrent < 0) //没有数据可读取
return (iRtxBytes);
iRtxBytes += iRtxCurrent;
}
return (iRtxBytes);
}
//一次性发送数据(重叠IO)
int TE_SendLL(SOCKET hSocket, char const * pszBuffer, int iBufferSize)
{
DWORD dwRtxBytes = 0;
WSABUF WSABuff;
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = iBufferSize;
WSABuff.buf = (char *) pszBuffer;
return ((WSASend(hSocket, &WSABuff, 1, &dwRtxBytes, 0,NULL, NULL) == SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
}
// 发送数据
int TE_SendData(SOCKET hSocket, char const * pszBuffer, int iBufferSize, DWORD dwTimeout)
{
HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hWriteEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
int iSendBytes = 0;
for (;;)
{
////////////////////////////////////////////////////////////////
// 发送数据成功
if ((iSendBytes = TE_SendLL(hSocket, pszBuffer, iBufferSize)) >= 0)
break;
int iErrorCode = -iSendBytes;
if (iErrorCode != WSAEWOULDBLOCK)
{
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
///////////////////////////////////////////////////////////////////////////////
// 睡眠一段时间
///////////////////////////////////////////////////////////////////////////////
Sleep(TE_BLOCKED_SNDRCV_SLEEP);
// 注册FD_WRITE | FD_CLOSE 事件
if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE|FD_CLOSE) == SOCKET_ERROR)
{
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
// 等待事件发生
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hWriteEvent, TRUE,dwTimeout, TRUE);
if (dwWaitResult != WSA_WAIT_EVENT_0)
{
// 清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hWriteEvent,&NetEvent) == SOCKET_ERROR)
{
// 清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
( NetEvent.lNetworkEvents == FD_WRITE &&
NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) ) // 发生错误
{
// 清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
// 清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
}
CloseHandle(hWriteEvent);
return (iSendBytes);
}
//发送完所有数据或超时
int TE_Send(SOCKET hSocket, char const * pszBuffer, int iBufferSize, DWORD dwTimeout)
{
int iRtxBytes = 0;
int iRtxCurrent = 0;
while (iRtxBytes < iBufferSize)
{
iRtxCurrent = TE_SendData(hSocket, (pszBuffer + iRtxBytes),(iBufferSize - iRtxBytes), dwTimeout);
if (iRtxCurrent < 0)
return (iRtxBytes);
iRtxBytes += iRtxCurrent;
}
return (iRtxBytes);
}
// 建立连接
int TE_Connect(SOCKET hSocket, const struct sockaddr * pSocketAddress, int iNameLen,DWORD dwTimeout)
{
HANDLE hConnectEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hConnectEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
// 注册FD_CONNECT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, FD_CONNECT) == SOCKET_ERROR)
{
CloseHandle(hConnectEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
int iConnectResult = WSAConnect(hSocket, pSocketAddress, iNameLen, NULL, NULL, NULL, NULL);
int iConnectError = WSAGetLastError();
if ((iConnectResult == SOCKET_ERROR) && (iConnectError == WSAEWOULDBLOCK))
{
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hConnectEvent, TRUE,dwTimeout, TRUE);
if (dwWaitResult != WSA_WAIT_EVENT_0)
{
TE_SetLastError( WSAGetLastError() );
iConnectResult = SOCKET_ERROR;
}
else
{
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hConnectEvent,&NetEvent) == SOCKET_ERROR)
{
TE_SetLastError( WSAGetLastError() );
iConnectResult = SOCKET_ERROR;
}
else if(NetEvent.iErrorCode[FD_CONNECT_BIT] !=0 ) // 发生错误
{
TE_SetLastError( NetEvent.iErrorCode[FD_CONNECT_BIT] );
iConnectResult = SOCKET_ERROR;
}
else
iConnectResult = SOCKET_SUCCESS;
////////////////////////////////////////////////////////////////
}
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, 0);
CloseHandle(hConnectEvent);
return (iConnectResult);
}
///////////////////////////////////////////////////////////
//
// 引入该函数的目的是为了避免NT下对域名解析的CACHE造成的问题
//
///////////////////////////////////////////////////////////
DWORD WINAPI DNSThread( LPVOID pParam )
{
DWORD dwIP = INADDR_NONE;
PHOSTENT pHost = gethostbyname( (char *)pParam );
if(pHost == NULL)
return INADDR_NONE;
dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
return dwIP;
}
DWORD TE_GetIP(const char* name,BOOL fFixNtDNS /* = FALSE*/) // Used to Fix NT DNS Problem
{
DWORD dwIP = inet_addr(name);
if( dwIP != INADDR_NONE )
return dwIP;
if( fFixNtDNS )
{
OSVERSIONINFO osVersion;
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if( GetVersionEx(&osVersion) )
{
if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL,0,DNSThread,(LPVOID)name,0,&dwThreadId);
if( hThread != NULL)
{
WaitForSingleObject(hThread,INFINITE);
if( GetExitCodeThread(hThread,&dwIP))
return dwIP;
}
}
}
}
PHOSTENT pHost = gethostbyname(name);
if(pHost == NULL)
return INADDR_NONE;
dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
return dwIP;
}
// 建立连接(扩展函数)
int TE_ConnectEx(SOCKET hSocket, char const * pszServer, int nPort,DWORD dwTimeout,BOOL fFixNtDNS /*= FALSE*/)
{
/////////////////////////////////////////////////////////////////////////////
SOCKADDR_IN sockAddr;
ZeroMemory(&sockAddr,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((u_short)nPort);
sockAddr.sin_addr.s_addr = TE_GetIP(pszServer,fFixNtDNS);
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
{
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////////////
return TE_Connect(hSocket, (SOCKADDR *)&sockAddr,sizeof(sockAddr),dwTimeout);
}
// 绑定套接字
int TE_BindSocket(SOCKET hSocket, const struct sockaddr * SockName, int iNameLen)
{
if (bind(hSocket, SockName, iNameLen) == SOCKET_ERROR)
{
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}
// 绑定套接字
int TE_BindSocketEx(SOCKET hSocket,int nPort)
{
SOCKADDR_IN sockAddr;
ZeroMemory(&sockAddr,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockAddr.sin_port = htons((u_short)nPort);
return TE_BindSocket(hSocket,(SOCKADDR *)&sockAddr, sizeof(sockAddr));
}
// 监听套接字
int TE_ListenSocket(SOCKET hSocket, int iConnections)
{
if(listen(hSocket, iConnections) == SOCKET_ERROR)
{
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}
// 接受套接字连接
SOCKET TE_Accept(SOCKET hSocket, struct sockaddr * pSocketAddress, int *iNameLen,DWORD dwTimeout)
{
HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hAcceptEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return (INVALID_SOCKET);
}
// 注册FD_ACCEPT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
{
CloseHandle(hAcceptEvent);
TE_SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
SOCKET hSocketAccept = WSAAccept(hSocket, pSocketAddress, iNameLen, NULL, 0);
int iConnectError = WSAGetLastError();
if ((hSocketAccept == INVALID_SOCKET) && (iConnectError == WSAEWOULDBLOCK))
{
// 阻塞
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hAcceptEvent, TRUE,dwTimeout, TRUE);
if (dwWaitResult == WSA_WAIT_EVENT_0)
{
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
TE_SetLastError( WSAGetLastError() );
else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
TE_SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
else
hSocketAccept = WSAAccept(hSocket, pSocketAddress, iNameLen, NULL, 0);
}
else
TE_SetLastError( WSAGetLastError() );
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
CloseHandle(hAcceptEvent);
if (hSocketAccept != INVALID_SOCKET)
{
// 设置套接字的属性为地址可重用并且为非阻塞的
if ( (TE_BlockSocket(hSocketAccept, 0) == SOCKET_ERROR ) ||
(TE_SetSocketOption(hSocketAccept) == SOCKET_ERROR ) )
{
TE_CloseSocket(hSocketAccept,TRUE);
return (INVALID_SOCKET);
}
}
return (hSocketAccept);
}
// 接受套接字连接(允许中断)
SOCKET TE_AcceptEx(SOCKET hSocket, struct sockaddr * pSockName, int *iNameLen,HANDLE hEndEvent,DWORD dwTimeout /*= TE_DEFAULT_TIMEOUT*/)
{
if( hEndEvent == NULL)
return TE_Accept(hSocket,pSockName,iNameLen,dwTimeout);
HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hAcceptEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return (INVALID_SOCKET);
}
WSAEVENT hEvent[2];
hEvent[0] = (WSAEVENT)hAcceptEvent;
hEvent[1] = (WSAEVENT)hEndEvent;
// 注册FD_ACCEPT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
{
CloseHandle(hAcceptEvent);
TE_SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
SOCKET hSocketAccept = WSAAccept(hSocket, pSockName, iNameLen, NULL, 0);
int iConnectError = WSAGetLastError();
if ((hSocketAccept == INVALID_SOCKET) && (iConnectError == WSAEWOULDBLOCK))
{
// 阻塞
DWORD dwWaitResult = WSAWaitForMultipleEvents(2, hEvent, FALSE,dwTimeout, TRUE);
if (dwWaitResult == WSA_WAIT_EVENT_0)
{
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
TE_SetLastError( WSAGetLastError() );
else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
TE_SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
else
hSocketAccept = WSAAccept(hSocket, pSockName, iNameLen, NULL, 0);
}
else
TE_SetLastError( WSAGetLastError() );
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
CloseHandle(hAcceptEvent);
if (hSocketAccept != INVALID_SOCKET)
{
// 设置套接字的属性为地址可重用并且为非阻塞的
if ( (TE_BlockSocket(hSocketAccept, 0) < 0) ||
(TE_SetSocketOption(hSocketAccept) < 0) )
{
TE_CloseSocket(hSocketAccept,TRUE);
return (INVALID_SOCKET);
}
}
return (hSocketAccept);
}
// 设置套接字是否为阻塞的
int TE_BlockSocket(SOCKET hSocket, BOOL bBlock)
{
u_long IoctlLong = (bBlock) ? 0 : 1;
if (ioctlsocket(hSocket, FIONBIO, &IoctlLong) == SOCKET_ERROR)
{
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}
// 数据报接收函数
int TE_RecvDataFrom( SOCKET hSocket, struct sockaddr * pFrom, int iFromlen,
char *pszBuffer, int iBufferSize, DWORD dwTimeout)
{
HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hReadEvent == NULL)
{
TE_SetLastError((int)GetLastError() );
return (SOCKET_ERROR);
}
DWORD dwRtxBytes = 0,
dwRtxFlags = 0;
WSABUF WSABuff;
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = iBufferSize;
WSABuff.buf = pszBuffer;
for (;;)
{
// 注册FD_READ事件
if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ) == SOCKET_ERROR)
{
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, TRUE, dwTimeout, TRUE);
if( dwWaitResult != WSA_WAIT_EVENT_0 )
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError());
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent) == SOCKET_ERROR)
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
if(NetEvent.iErrorCode[FD_READ_BIT] !=0 ) // 发生错误
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
TE_SetLastError(NetEvent.iErrorCode[FD_READ_BIT]);
return (SOCKET_ERROR);
}
////////////////////////////////////////////////////////////////
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
int FromLen = iFromlen;
if ( WSARecvFrom(hSocket, &WSABuff, 1, &dwRtxBytes, &dwRtxFlags,pFrom, &FromLen, NULL, NULL) == SOCKET_SUCCESS )
break;
if ( WSAGetLastError() != WSAEWOULDBLOCK)
{
CloseHandle(hReadEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
///////////////////////////////////////////////////////////////////////////
// 睡眠一段时间
//////////////////////////////////////////////////////////////////////////
Sleep(TE_BLOCKED_SNDRCV_SLEEP);
}
CloseHandle(hReadEvent);
return ((int) dwRtxBytes);
}
// 数据报发送数据报
int TE_SendDataTo(SOCKET hSocket, const struct sockaddr * pTo,int iToLen,
char const * pszBuffer, int iBufferSize, DWORD dwTimeout)
{
HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hWriteEvent == NULL)
{
TE_SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
DWORD dwRtxBytes = 0,
dwRtxFlags = 0;
WSABUF WSABuff;
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = iBufferSize;
WSABuff.buf = (char *) pszBuffer;
for (;;)
{
if (WSASendTo( hSocket, &WSABuff, 1, &dwRtxBytes, dwRtxFlags,pTo, iToLen, NULL, NULL) == SOCKET_SUCCESS)
break;
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////////////////
// 睡眠一段时间
/////////////////////////////////////////////////////////////////////////
Sleep(TE_BLOCKED_SNDRCV_SLEEP);
// 注册FD_WRITE事件
if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE) == SOCKET_ERROR)
{
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hWriteEvent, TRUE,dwTimeout, TRUE);
if( dwWaitResult != WSA_WAIT_EVENT_0 )
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//////////////////////////////////////////////////////////////
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///////////////////////////////////////////////////////////////
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hWriteEvent,&NetEvent) == SOCKET_ERROR)
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
if(NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) // 发生错误
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
TE_SetLastError(NetEvent.iErrorCode[FD_WRITE_BIT]);
return (SOCKET_ERROR);
}
////////////////////////////////////////////////////////////////
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
}
CloseHandle(hWriteEvent);
return ((int) dwRtxBytes);
}
////////////////////////////////////////////////////////////////////////////////
//
// BSocket函数
//
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// 功能: 绑定套接字
// 参数:
// hSocket -- SOCKET(待绑定套接字)
// iBufferSize -- 缓冲区长度(缺省为TE_SOCKET_BUFFER_SIZE)
// 返回:
// 结构指针(失败时为NULL)
//
////////////////////////////////////////////////////////////////////////////////
PBSD TE_BSocketAttach(SOCKET hSocket, int iBufferSize /* = TE_SOCKET_BUFFER_SIZE */ )
{
if( hSocket == INVALID_SOCKET)
return NULL;
// 分配内存
PBSD pBSD = (PBSD) malloc(sizeof(BSD));
if (pBSD == NULL)
return NULL;
char *pszBuffer = (char *) malloc(iBufferSize);
if (pszBuffer == NULL)
{
free(pBSD);
return NULL;
}
// 设置结构成员
ZeroMemory(pBSD,sizeof(BSD));
ZeroMemory(pszBuffer,iBufferSize);
pBSD->hSocket = hSocket;
pBSD->iBufferSize = iBufferSize;
pBSD->pszBuffer = pszBuffer;
pBSD->iBytesInBuffer = 0;
pBSD->iReadIndex = 0;
pBSD->iBufferIndex = 0;
return pBSD;
}
////////////////////////////////////////////////////////////////////////////
//
// 功能: 解开套接字
// 参数:
// pBSD -- BufSocketData结构指针
// bCloseSocket -- 是否在解开套接字同时关闭套接字(缺省为FALSE)
// 返回:
// 若bCloseSocket为FALSE,返回解开的套接字
// 若bCloseSocket为TRUE ,返回INVALID_SOCKET
//
///////////////////////////////////////////////////////////////////////////
SOCKET TE_BSocketDetach(PBSD pBSD, BOOL bCloseSocket /* = FALSE */ )
{
SOCKET hSocket = pBSD->hSocket;
// 释放内存
free(pBSD->pszBuffer);
free(pBSD);
// 是否关闭套接字
if (bCloseSocket)
{
TE_CloseSocket(hSocket);
return (INVALID_SOCKET);
}
return (hSocket);
}
////////////////////////////////////////////////////////////////////
//
// 功能: 从缓冲区读取数据
// 参数:
// pBSD -- BufSocketData结构指针
// dwTimeOut -- 接收超时(缺省为TE_RECV_TIMEOUT)
// 返回:
// 0 --- 成功 (SOCKET_SUCCESS)
// -1 --- 失败 (SOCKET_ERROR)
//
////////////////////////////////////////////////////////////////////
int TE_BSocketReadData(PBSD pBSD, DWORD dwTimeout /* = TE_RECV_TIMEOUT */ )
{
// 计算缓冲区空闲区域
int iMaxRead = pBSD->iBufferSize - pBSD->iBytesInBuffer;
char *pszBuffer = (char *) malloc(iMaxRead + 1);
if (pszBuffer == NULL)
return (SOCKET_ERROR);
// 清空
ZeroMemory(pszBuffer,iMaxRead+1);
// 接收数据
int iReadedBytes = TE_RecvData(pBSD->hSocket, pszBuffer, iMaxRead, dwTimeout);
if (iReadedBytes > 0)
{
int iHeadSize = Min(pBSD->iBufferSize - pBSD->iBufferIndex, iReadedBytes);
if (iHeadSize > 0)
memcpy(pBSD->pszBuffer + pBSD->iBufferIndex, pszBuffer, iHeadSize);
pBSD->iBufferIndex += iHeadSize;
if (pBSD->iBufferIndex == pBSD->iBufferSize)
pBSD->iBufferIndex = 0;
int iBackSize = iReadedBytes - iHeadSize;
if (iBackSize > 0)
memcpy(pBSD->pszBuffer + pBSD->iBufferIndex, pszBuffer + iHeadSize, iBackSize);
pBSD->iBufferIndex += iBackSize;
pBSD->iBytesInBuffer += iReadedBytes;
}
free(pszBuffer);
return (iReadedBytes);
}
////////////////////////////////////////////////////////////////////
//
// 功能: 从缓冲区读取一个字符
// 参数:
// pBSD -- BufSocketData结构指针
// dwTimeOut -- 接收超时(缺省为TE_RECV_TIMEOUT)
// 返回:
// 一个字符(错误时返回TE_EOF)
//
////////////////////////////////////////////////////////////////////
int TE_BSocketGetChar(PBSD pBSD, DWORD dwTimeout /* = TE_RECV_TIMEOUT */ )
{
if ((pBSD->iBytesInBuffer == 0) && (TE_BSocketReadData(pBSD, dwTimeout) <= 0))
return (TE_EOF);
int iChar =( (int) pBSD->pszBuffer[pBSD->iReadIndex]) & 0x000000ff;
pBSD->iReadIndex = INext(pBSD->iReadIndex, pBSD->iBufferSize);
--pBSD->iBytesInBuffer;
return (iChar);
}
////////////////////////////////////////////////////////////////////////////
//
// 功能: 从缓冲区读取一行(注意,结尾的回车换行0x0D,0x0A并不包括在其中)
// 参数:
// pBSD -- BufSocketData结构指针
// pszBuffer -- 接收缓冲区
// iBufferSize -- 缓冲大小
// iStatus -- 状态 (0:正常,1:缓冲不够,-1:错误)
// dwTimeOut -- 接收超时(缺省为TE_RECV_TIMEOUT)
// 返回:
// 0 --- 成功 (SOCKET_SUCCESS)
// -1 --- 失败 (SOCKET_ERROR)
//
////////////////////////////////////////////////////////////////////////////
int TE_BSocketGetString(PBSD pBSD, char *pszBuffer, int iBufferSize, int* iStatus, DWORD dwTimeout /* = TE_RECV_TIMEOUT */ )
{
*iStatus = 1; //缓冲长度不足
int ii,iChar;
for (ii = 0; ii < (iBufferSize - 1);)
{
iChar = TE_BSocketGetChar(pBSD, dwTimeout);
if (iChar == TE_EOF)
{
*iStatus = (-1) ;
return SOCKET_ERROR;
}
if (iChar == 0x0D) // 回车符号
{
iChar = TE_BSocketGetChar(pBSD, dwTimeout);
if (iChar == TE_EOF)
{
*iStatus = (-1);
return (SOCKET_ERROR);
}
if (iChar == 0x0A) // 换行
{
*iStatus = 0; //正常情况
break;
}
else
pszBuffer[ii++] = 0x0D;
}
else
pszBuffer[ii++] = (char) iChar;
}
pszBuffer[ii] = '\0';
return (SOCKET_SUCCESS);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// 功能: 从缓冲区读取一行(包括单换行0x0A)(注意,结尾的回车换行不包括在其中)
// 参数:
// pBSD -- BufSocketData结构指针
// pszBuffer -- 接收缓冲区
// iBufferSize -- 缓冲大小
// iStatus -- 状态 (0:正常,1:缓冲不够,-1:错误)
// dwTimeOut -- 接收超时(缺省为TE_RECV_TIMEOUT)
// 返回:
// 0 --- 成功 (SOCKET_SUCCESS)
// -1 --- 失败 (SOCKET_ERROR)
//
//////////////////////////////////////////////////////////////////////////////////////////
int TE_BSocketGetStringEx(PBSD pBSD, char *pszBuffer, int iBufferSize, int* iStatus, DWORD dwTimeout /* = TE_RECV_TIMEOUT */ )
{
*iStatus = 1; //缓冲长度不足
int ii,iChar;
int LastChar = TE_EOF;
for (ii = 0; ii < (iBufferSize - 1);)
{
iChar = TE_BSocketGetChar(pBSD, dwTimeout);
if (iChar == TE_EOF)
{
*iStatus = (-1) ;
return SOCKET_ERROR;
}
if (iChar == 0x0A) // 换行符号
{
*iStatus = 0; //正常情况
if (LastChar == 0x0D)
ii-- ;
break;
}
else
pszBuffer[ii++] = (char) iChar;
LastChar = iChar;
}
pszBuffer[ii] = '\0';
return (SOCKET_SUCCESS);
}
////////////////////////////////////////////////////////////////////
//
// 功能: 发送一行 : 自动在最后加上“回车换行符(0x0D,0x0A)”
// 参数:
// pBSD -- BufSocketData结构指针
// pszBuffer -- 待发送字符串
// dwTimeOut -- 发送超时(缺省为TE_SEND_TIMEOUT)
// 返回:
// 0 --- 成功 (SOCKET_SUCCESS)
// -1 --- 失败 (SOCKET_ERROR)
//
////////////////////////////////////////////////////////////////////
int TE_BSocketSendString(PBSD pBSD, const char *pszBuffer, DWORD dwTimeout /* = TE_SEND_TIMEOUT */ )
{
char *pszSendBuffer = (char *) malloc(strlen(pszBuffer) + 3);
if (pszSendBuffer == NULL)
return (SOCKET_ERROR);
ZeroMemory( pszSendBuffer,strlen(pszBuffer) + 3);
sprintf(pszSendBuffer, "%s\r\n", pszBuffer);
int iSendLength = strlen(pszSendBuffer);
if (TE_Send(pBSD->hSocket, pszSendBuffer, iSendLength, dwTimeout) != iSendLength)
{
free(pszSendBuffer);
return (SOCKET_ERROR);
}
free(pszSendBuffer);
return (iSendLength);
}
////////////////////////////////////////////////////////////////////
//
// 功能: 获取套接字
// 参数:
// pBSD -- BufSocketData结构指针
// 返回:
// 与此结构绑定在一起的SOCKET
//
////////////////////////////////////////////////////////////////////
SOCKET TE_BSocketGetAttachedSocket(PBSD pBSD)
{
return (pBSD->hSocket);
}
////////////////////////////////////////////////////////////////////
//
// 功能: 从缓冲区读取一定数量的数据
// 参数:
// pBSD -- BufSocketData结构指针
// pszBuffer -- 接收缓冲区
// iBufferSize -- 缓冲大小
// dwTimeOut -- 接收超时(缺省为TE_RECV_TIMEOUT)
// 返回:
// 读的数据的字节数
////////////////////////////////////////////////////////////////////
int TE_BSocketGetData(PBSD pBSD, char *pszBuffer, int iBufferSize,DWORD dwTimeout /*= TE_RECV_TIMEOUT*/)
{
int iReadBytes = 0;
int iHeadSize,iBackSize;
if ((pBSD->iBytesInBuffer == 0) && (TE_BSocketReadData(pBSD, dwTimeout) <= 0))
return 0;
if( pBSD->iBytesInBuffer < iBufferSize ) // 数据不够多
{
iHeadSize = Min( pBSD->iBufferSize - pBSD->iReadIndex ,pBSD->iBytesInBuffer );
memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iHeadSize);
pBSD->iReadIndex += iHeadSize;
if( pBSD->iReadIndex == pBSD->iBufferSize )
pBSD->iReadIndex = 0;
iReadBytes += iHeadSize;
iBackSize = pBSD->iBytesInBuffer - iHeadSize;
if( iBackSize > 0)
memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iBackSize);
iReadBytes += iBackSize;
pBSD->iReadIndex += iBackSize;
pBSD->iBytesInBuffer = 0; // 数据全部读完
}
else // 这次的数据足够多了
{
iHeadSize = Min( pBSD->iBufferSize - pBSD->iReadIndex,iBufferSize - iReadBytes );
memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iHeadSize);
pBSD->iReadIndex += iHeadSize;
if( pBSD->iReadIndex == pBSD->iBufferSize )
pBSD->iReadIndex = 0;
iReadBytes += iHeadSize;
iBackSize = iBufferSize - iReadBytes;
if( iBackSize > 0)
memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iBackSize);
iReadBytes += iBackSize;
pBSD->iReadIndex += iBackSize;
pBSD->iBytesInBuffer -= (iHeadSize+iBackSize);
}
return iReadBytes;
}