CAsyncSocket類是VC++的MFC裡一個對WinSock API封裝得很低級的一個類。適合於既想利用WinSock API的靈活性,又想享受MFC裡的消息事件機制帶來的方便情況下使用,但是CAsyncSocket不支持IPX/SPX協議。筆者最近在開發一個基於IPX/SPX協議傳送SPX包的程序時候,重載了CAsyncSocket類的Create,Bind,Connect,Socket,Accept這五個成員函數,成功地使CAsyncSocket類支持了IPX/SPX協議。下面談談具體實現。
我們先看看AsyncSocket::Create()這個函數的定義
BOOL Create(UINT nSocketPort = 0, int nSocketType=SOCK_STREAM,
long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL);
第一個參數是套接字的端口,第二個參數是套接字的類型,默認為流式套接字。第三個參數是針對套接字產生的事件,第四個參數是套接字的地址,默認為NULL。下面是這個函數的實現:
BOOL CAsyncSocket::Create(UINT nSocketPort, int nSocketType,
long lEvent, LPCTSTR lpszSocketAddress)
{
if (Socket(nSocketType, lEvent))
{
if (Bind(nSocketPort,lpszSocketAddress))
return TRUE;
int nResult = GetLastError();
Close();
WSASetLastError(nResult);
}
return FALSE;
}
請仔細看上面的代碼,其實Create函數就調用了兩個函數,一個是Socket,一個是Bind.從上面這段代碼裡,我們還看不出是CAsyncSocket類對TCP/IP和IPX/SPX協議的處理不同之處。
那麼我們就接下來看看Socket函數
BOOL Socket(int nSocketType=SOCK_STREAM, long lEvent =
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
int nProtocolType = 0, int nAddressFormat = PF_INET);
接下來是Socket函數的實現
BOOL CAsyncSocket::Socket(int nSocketType, long lEvent,
int nProtocolType, int nAddressFormat)
{
ASSERT(m_hSocket == INVALID_SOCKET);
m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType);
if (m_hSocket != INVALID_SOCKET)
{
CAsyncSocket::AttachHandle(m_hSocket, this, FALSE);
return AsyncSelect(lEvent);
}
return FALSE;
}
看清楚了,裡面有一句
m_hSocket=socket(nAddressFormat,nSocketType,nProtocolType);
我想熟悉WinSock API編程的朋友一定會知道,其實這就是WinSock API裡創建一個新的套接字。第一個參數nAddressFormat就是套接字使用的協議族,在winsock2.h裡我們可以找到
#define PF_INET AF_INET
#define PF_IPX AF_IPX
這兩個定義,PF_INET就是指我們新創建的套接字使用TCP/IP協議,PF_IPX就是使用IPX/SPX協議。
而第二個參數nSocketType默認的就是流式套接字,第三個參數nProtocolType是指定使用的協議類型。
在winsock2.h裡有這樣的定義
#define IPPROTO_IP 0
默認的參數0就是IP包。
在使用默認參數調用Create函數情況下,即
CAsyncSocket::Create();
到了CAsyncSocket::Socket函數
m_hSocket=socket(nAddressFormat,nSocketType,nProtocolType);
這一句這裡就變成了
m_hSocket=socket(AF_INET,SOCK_STREAM,IPROTO_IP);
我想現在大家都已經很清楚了CAsyncSocket類之所以不支持IPX/SPX協議問題就在這一句上面,因為他默認的創建一個基於TCP/IP的流式或者數據包套接字。我們要讓CAsyncSocket類支持IPX/SPX,首先就要修改這裡。
而在WinSock API裡,創建一個基於IPX/SPX協議傳送SPX包的流式套接字應該是這樣
SOCKET sdServer;
SOCKADDR_IPX IPXAddr;
int addrlen=sizeof(SOCKADDR_IPX);
sdServer=socket(AF_IPX,SOCK_STREAM,NSPROTO_SPX);
ZeroMemory(&IPXAddr,sizeof(SOCKADDR_IPX));
IPXAddr.safamily=AF_IPX;
IPXAddr.sa_socket=hotns(9000);
bind(sdServer,(PSOCKADDR)&IPXAddr,sizeof(SOCKADDR_IPX);
IPX應用程序通過bind把本地地址與套接字綁定在一起,綁定端口是9000。我們不需要在SOCKADDR_IPX裡指定網絡號和節點地址,bind函數會自動利用系統上第一個可用IPX網絡接口來填充這些SOCKADDR_IPX結構裡的相應字段。
所以我們在自己的類裡重載的Socket函數應該是這樣
BOOL Socket(int flg,int nSocketType=SOCK_STREAM, long lEvent =
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
int nProtocolType = NSPROTO_SPX, int n