CAsynSocket似乎总难满足要求,不能跨线程使用应该是它的致命伤,直接使用socket是最好的办法,这也是许多大牛们推荐的方法。为了避免重复劳动,自己封装了一个CMySocket类,希望能像CAsynSocket一样使用(现在还不可能了,偶也是初学,只有慢慢完善,也许有一天能接近CAsynSocket ),既然是自己封装的类,是否线程安全就自己说了算了,呵呵。
目前实现如下功能:
创建socket、数据收发(TCP和UDP)、收发缓冲区大小设置等。
IO模型采用WSAEventSelect机制。
用它实现了局域网的聊天程序,挺好用。如有不恰当的地方,请给我留言,我会将其逐步完善!
使用方法:
继承CMySocket类,重载OnAccept、OnReceive等函数(和CAsyncSocket方法相同)。不用调用AfxSocketInit函数,因为该函数所作工作在我封装的代码中已完成。
下面是代码
******************************头文件 MySocket.h***********************
#ifndef __MYSOCKET_H__
#define __MYSOCKET_H__
#include <WINSOCK2.H>
#define MAX_SOCKET 64
#pragma comment(lib,"Ws2_32.lib")
typedef struct tagClient
{
sockaddr addr;
SOCKET sock;
}TClient;
class CMySocket
{
public:
CMySocket();
CMySocket(const CMySocket&);
~CMySocket();
static int StartUp();
int Create(int port,int socket_type,long lEvent=FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
int Close();
int Listen(int backlog=SOMAXCONN);
int Accept(CMySocket* pSocket,struct sockaddr* addr);
int Connect(const char* IP,int port);
int Receive(char* buf,int len);
int Receive(char* buf,int len,char* IP,int* port);
int Send(char* buf,int len);
int Send(char* buf,int len,const char* IP,int port);
int GetRcvBufSize(int* bufsize,int* len);
int GetSndBufSize(int* bufsize,int* len);
int SetRcvBufSize(int* bufsize,int len);
int SetSndBufSize(int* bufsize,int len);
CMySocket operator = (CMySocket& mySocket1);
virtual void OnAccept(int errorcode);
virtual void OnConnect(int errorcode);
virtual void OnReceive(int errorcode);
virtual void OnSend(int errorcode);
virtual void OnClose(int errorcode);
static void GetSocketAddr(struct sockaddr* addr);
static void RemoveSocket(SOCKET s);
SOCKET m_socket;
int m_nSocketType;
long m_lEvent;
BOOL m_bThreadStarted;
BOOL m_bEndTread;
static int m_nClientNum;
static TClient clientList[MAX_SOCKET];
static SOCKET socketArray[MAX_SOCKET];
static WSAEVENT eventArrray[MAX_SOCKET];
static int m_totalSocket;
static DWORD m_dwIndex;
static CRITICAL_SECTION m_cs;
protected:
static int m_nInstnum;
static BOOL m_bStartUp;
static BOOL m_bInitCS;
private:
};
#endif
***************************代码实现 MySocket.cpp*****************************
#include "stdafx.h"
#include "MySocket.h"
#include <process.h>
void SocketThread(void* parm);
TClient CMySocket::clientList[MAX_SOCKET];
SOCKET CMySocket::socketArray[MAX_SOCKET];
WSAEVENT CMySocket::eventArrray[MAX_SOCKET];
int CMySocket::m_totalSocket = 0;
int CMySocket::m_nInstnum = 0;
int CMySocket::m_nClientNum = 0;
DWORD CMySocket::m_dwIndex = 0;
BOOL CMySocket::m_bStartUp = FALSE;
BOOL CMySocket::m_bInitCS = FALSE;
CRITICAL_SECTION CMySocket::m_cs;
CMySocket::CMySocket()
{
m_socket = INVALID_SOCKET;
m_bThreadStarted = FALSE;
m_bEndTread = FALSE;
m_nInstnum++;
if (!m_bInitCS)
{
InitializeCriticalSection(&m_cs);
m_bInitCS = TRUE;
}
}
CMySocket::CMySocket(const CMySocket& myScoket)
{
m_socket = myScoket.m_socket;
m_nSocketType = myScoket.m_nSocketType;
}
CMySocket::~CMySocket()
{
m_nInstnum--;
if (m_socket != INVALID_SOCKET)
{
closesocket(m_socket);
}
if (!m_nInstnum)
{
WSACleanup();
m_bStartUp = FALSE;
}
}
int CMySocket::StartUp()
{
if (!m_bStartUp)
{
WSADATA wsaData;
if (WSAStartup(WINSOCK_VERSION,&wsaData))
{
int err = WSAGetLastError();
return err;
}
}
return 0;
}
int CMySocket::Create(int port,int socket_type,long lEvent)
{
if (!m_bStartUp)
{
StartUp();
}
if (m_socket != INVALID_SOCKET)
{
return 0;
}
m_nSocketType = socket_type;
m_socket = socket(AF_INET,m_nSocketType,0);
if (m_socket == INVALID_SOCKET)
{
int err = WSAGetLastError();
return err;
}
else
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(m_socket,(LPSOCKADDR)&addr,sizeof(addr)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
}
WSAEVENT wsaEvent = WSACreateEvent();
if (WSAEventSelect(m_socket,wsaEvent,lEvent))
{
int err = WSAGetLastError();
return err;
}
EnterCriticalSection(&m_cs);
socketArray[m_totalSocket] = m_socket;
eventArrray[m_totalSocket] = wsaEvent;
m_totalSocket++;
LeaveCriticalSection(&m_cs);
m_bEndTread = FALSE;
if (_beginthread(SocketThread,0,this) == -1)
{
return -1;
}
int loopnum = 0;
while (!m_bThreadStarted)
{
loopnum++;
if (loopnum > 200)
{
return -1;
}
Sleep(10);
}
return 0;
}
int CMySocket::Close()
{
RemoveSocket(m_socket);
if (closesocket(m_socket) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
m_socket = INVALID_SOCKET;
m_bEndTread = TRUE;
return 0;
}
int CMySocket::Listen(int backlog)
{
if (listen(m_socket,backlog) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
return 0;
}
int CMySocket::Accept(CMySocket* pSocket,struct sockaddr* addr)
{
SOCKET sock;
int len = sizeof(struct sockaddr);
if ((sock = accept(m_socket,addr,&len)) == INVALID_SOCKET)
{
int err = WSAGetLastError();
return err;
}
pSocket->m_socket = sock;
pSocket->m_nSocketType = SOCK_STREAM;
WSAEVENT wsaEvent = WSACreateEvent();
if (WSAEventSelect(sock,wsaEvent,FD_READ | FD_CLOSE))
{
int err = WSAGetLastError();
return err;
}
EnterCriticalSection(&m_cs);
socketArray[m_totalSocket] = sock;
eventArrray[m_totalSocket] = wsaEvent;
m_totalSocket++;
int index = m_nClientNum;
clientList[index].addr = *addr;
clientList[index].sock = sock;
m_nClientNum++;
LeaveCriticalSection(&m_cs);
return 0;
}
int CMySocket::Connect(const char* IP,int port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr(IP);
addr.sin_port = htons(port);
if (connect(m_socket,(LPSOCKADDR)&addr,sizeof(addr)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
return 0;
}
void CMySocket::RemoveSocket(SOCKET s)
{
int i,j;
EnterCriticalSection(&m_cs);
int totalSocket = m_totalSocket;
for (i=0;i<totalSocket;i++)
{
if (CMySocket::socketArray[i] == s)
{
for (j=i;j<totalSocket-1;j++)
{
socketArray[j] = socketArray[j+1];
eventArrray[j] = eventArrray[j+1];
}
m_totalSocket--;
break;
}
}
int num = m_nClientNum;
for (i=0;i<num;i++)
{
if (clientList[i].sock == s)
{
for (j=i;j<num-1;j++)
{
clientList[j].sock = clientList[j+1].sock;
clientList[j].addr = clientList[j+1].addr;
}
m_nClientNum--;
break;
}
}
LeaveCriticalSection(&m_cs);
}
void SocketThread(void* parm)
{
CMySocket *pMySocket = (CMySocket*)parm;
WSANETWORKEVENTS tEvent;
DWORD ret;
DWORD dwIndex;
int errorcode;
int timeout = 10;
pMySocket->m_bThreadStarted = TRUE;
while (1)
{
EnterCriticalSection(&CMySocket::m_cs);
ret = WSAWaitForMultipleEvents(CMySocket::m_totalSocket,CMySocket::eventArrray,FALSE,timeout,FALSE);
LeaveCriticalSection(&CMySocket::m_cs);
if (pMySocket->m_bEndTread)
{
_endthread();
}
if (ret == WSA_WAIT_TIMEOUT)
{
continue;
}
dwIndex = ret;
dwIndex -= WSA_WAIT_EVENT_0;
CMySocket::m_dwIndex = dwIndex;
memset(&tEvent,0,sizeof(WSANETWORKEVENTS));
EnterCriticalSection(&CMySocket::m_cs);
WSAEnumNetworkEvents(CMySocket::socketArray[dwIndex],CMySocket::eventArrray[dwIndex],&tEvent);
WSAResetEvent(CMySocket::eventArrray[dwIndex]);
LeaveCriticalSection(&CMySocket::m_cs);
if (tEvent.lNetworkEvents & FD_CONNECT)
{
errorcode = tEvent.iErrorCode[FD_CONNECT_BIT];
pMySocket->OnConnect(errorcode);
}
else if (tEvent.lNetworkEvents & FD_ACCEPT)
{
errorcode = tEvent.iErrorCode[FD_ACCEPT_BIT];
pMySocket->OnAccept(errorcode);
}
else if (tEvent.lNetworkEvents & FD_READ)
{
DWORD nBytes = 0;
errorcode = tEvent.iErrorCode[FD_READ_BIT];
ioctlsocket(CMySocket::socketArray[dwIndex],FIONREAD,&nBytes);
if (nBytes > 0)
pMySocket->OnReceive(errorcode);
}
else if (tEvent.lNetworkEvents & FD_WRITE)
{
errorcode = tEvent.iErrorCode[FD_WRITE_BIT];
pMySocket->OnSend(errorcode);
}
else if (tEvent.lNetworkEvents & FD_CLOSE)
{
errorcode = tEvent.iErrorCode[FD_CLOSE_BIT];
pMySocket->OnClose(errorcode);
CMySocket::RemoveSocket(CMySocket::socketArray[dwIndex]);
}
else
{
}
}
}
int CMySocket::Receive(char* buf,int len)
{
sockaddr addr;
int size = sizeof(addr);
switch(m_nSocketType)
{
case SOCK_DGRAM:
if (recvfrom(m_socket,buf,len,0,&addr,&size) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
break;
case SOCK_STREAM:
if (recv(m_socket,buf,len,0) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
break;
default:
break;
}
return 0;
}
int CMySocket::Receive(char* buf,int len,char* IP,int* port)
{
sockaddr addr;
int size = sizeof(addr);
sockaddr_in* pAddr_in;
switch(m_nSocketType)
{
case SOCK_DGRAM:
if (recvfrom(m_socket,buf,len,0,&addr,&size) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
pAddr_in = (sockaddr_in*)&addr;
strcpy(IP,inet_ntoa(pAddr_in->sin_addr));
*port = ntohs(pAddr_in->sin_port);
break;
case SOCK_STREAM:
if (recv(m_socket,buf,len,0) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
break;
default:
break;
}
return 0;
}
int CMySocket::Send(char* buf,int len)
{
if (send(m_socket,buf,len,0) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
return 0;
}
int CMySocket::Send(char* buf,int len,const char* IP,int port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr(IP);
addr.sin_port = htons(port);
switch(m_nSocketType)
{
case SOCK_DGRAM:
if (sendto(m_socket,buf,len,0,(LPSOCKADDR)&addr,sizeof(addr)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
break;
case SOCK_STREAM:
if (send(m_socket,buf,len,0) == SOCKET_ERROR)
{
int err = WSAGetLastError();
return err;
}
break;
default:
break;
}
return 0;
}
int CMySocket::GetRcvBufSize(int* bufsize,int* len)
{
if (getsockopt(m_socket,SOL_SOCKET,SO_RCVBUF,(char*)bufsize,len))
{
int err = WSAGetLastError();
return err;
}
return 0;
}
int CMySocket::GetSndBufSize(int* bufsize,int* len)
{
if (getsockopt(m_socket,SOL_SOCKET,SO_SNDBUF,(char*)bufsize,len))
{
int err = WSAGetLastError();
return err;
}
return 0;
}
int CMySocket::SetRcvBufSize(int* bufsize,int len)
{
if (setsockopt(m_socket,SOL_SOCKET,SO_RCVBUF,(char*)bufsize,len))
{
int err = WSAGetLastError();
return err;
}
return 0;
}
int CMySocket::SetSndBufSize(int* bufsize,int len)
{
if (setsockopt(m_socket,SOL_SOCKET,SO_SNDBUF,(char*)bufsize,len))
{
int err = WSAGetLastError();
return err;
}
return 0;
}
CMySocket CMySocket::operator = (CMySocket& mySocket1)
{
CMySocket newScoket;
newScoket.m_socket = mySocket1.m_socket;
newScoket.m_nSocketType = mySocket1.m_nSocketType;
return newScoket;
}
void CMySocket::GetSocketAddr(struct sockaddr* addr)
{
EnterCriticalSection(&m_cs);
int num = m_nClientNum;
for (int i=0;i<num;i++)
{
if (clientList[i].sock == socketArray[m_dwIndex])
{
*addr = clientList[i].addr;
LeaveCriticalSection(&m_cs);
return;
}
}
addr->sa_data[0] = 0;
LeaveCriticalSection(&m_cs);
}
void CMySocket::OnReceive(int errorcode)
{
}
void CMySocket::OnAccept(int errorcode)
{
}
void CMySocket::OnClose(int errorcode)
{
}
void CMySocket::OnConnect(int errorcode)
{
}
void CMySocket::OnSend(int errorcode)
{
}