天
天 剑
用Visual C++ 6.0实现Windows 98 Socket编程
Windows 95 Socket 提供了在Microsoft Windows 95 中进行 网络程序设计的一个接口,它是在 Unix Socket 的基础上发 展而来的,不仅保留了Unix Socket 原有的风格,而且还融 入了适合于 Windows 95 的新特点,这使得用户可以利用 Windows 95 Socket API 直接进行进程与应用程序间的通信。Windows 95 在 Internet 支配域中的TCP/IP协议定义了Socket编写规程,使用 Socket 的目的是使用户在网络协议上工作而不必对该 网络协议有非常深入的了解。此外,这样编写的程序 可被迅速移植到任何支持 Socket 的网络系统中去。
Microsoft Windows Class Library(MFC) 中提供了 CSocket 类用来 实现网络通信。图一中给出了CSocket类的继承关系。
下面将介绍用Visual C++ 4.0在 Windows 95 中实现Socket的 CSocket 类关成员函数( 这些成员函数实际上是从CAsyncSocket 类继承来的)。
(1) 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 )
该函数用来建立Socket。其中,nSocketPort 为所选择的Socket端口,一般要大于1023,如果该参数为 0,则由系统选定一端口,默认值为 0;nSocketType为套接字类型:SOCK_STREAM表 示为流套接字,SOCK_DGRAM 表示为数据报套接字,默认值为 SOCK_STREAM ;lEvent 标识该 Socket 要完成哪种工作,默认值为FD_READ|FD_WRITE|FD_OOB| FD_ACCEPT|FD_CONNECT|FD_CLOSE ;
lpszSockAddress 为网络地址信息结构指针,包含网络地址,默认值为NULL。
(2)BOOL Bind( UINT nSocketPort,
LPCTSTR lpszSocketAddress = NULL )
该函数的作用是将 Socket 端口与网络地址连接起来。参数含义同上。
(3)BOOL Listen( int nConnectionBacklog = 5 )
该函数的作用是等待Socket请求。其中,nConnec-tionBacklog 表示等待队列的长度,默认值为最大值5。
(4)virtual BOOL Accept( CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL )
该函数的作用是取得队列上第一个连接请求并建立一个具有与Socket相同特性的套接字。其中,rConnectedSocket表示一个新的Socket。
(5)BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort )
该函数的作用是提出请求。其中,lpszHostAddress和nHostPort为接受请求进程的网络地址和Socket端口号。
(6)virtual void Close( )
该函数的作用是关闭该 Socket。
利用 CSocket 类直接进行数据通信有两种方式:一 种是利用 CSocketFile 类和 Archive 类去实现,另一种是利用 CSocket 的成员函数 Receive、Send、ReceiveFrom、SendTo、Listen和Accept等 来实现(这些成员函数实际上也是从CAsyncSocket类继承的)。
两种方法的实现步骤如下:
Server: Construct->Creat->Bind->Listen->Accept->Send->Close ;
Cilent: Construct->Creat->Connect->Receive-> Close。
下面我就用Visual C++ 4.0 的代码段分别介绍如何运用上述两种方法来实现Socket编 程。
1、利用 CSocketFile 类和 Archive 类实现
(1)Server
// construct a socket
CSocket sockSrvr;
// create the SOCKET
sockSrvr.Create(nPort);
// start listening
sockSrvr.Listen( );
//construct a new, empty socket
CSocket sockRecv;
// accept connection
sockSrvr.Accept( sockRecv );
// construct file object
CSocketFile file(&sockRecv);
// construct an archive
CArchive arIn(&file, CArchive::load);
/*or*/_CArchive arOut(&file, CArchive::store);
// use the archive to pass data
arIn >> dwValue;
/*or*/ arOut;
(2)Client
// construct a socket
CSocket sockClient;
// create the SOCKET
sockClient.Create( );
// seek a connection
sockClient.Connect(strAddr, nPort);
// construct file object
CSocketFile file(&sockClient);
// construct an archive
CArchive arIn(&file, CArchive::load);
/*or*/_CArchive arOut(&file, CArchive::store);
// use the archive to pass data
arOut /*or*/ arIn>> dwValue;
上述为Client/Server模式的两个进程,用于完成两个进程间一个数据变量的通信。其中 nPort 是Socket的端口 号,strAddr 是该机器的IP地址(如 202.197.1.3 或 FTP://RedAlert.com 等),这两个变量在Server和Client中要一致。当Server 进程运行至 Listen 后便处于睡眠状态直到 Client 进程执行 Connect 时才被唤醒,而后两个进程便开始传输数据了。
2、利用 CSocket 的成员函数实现
(1)Server
// Socket initial
if(!AfxSocketInit())
{
MessageBox("WindowsSocket initial
failed!","Send",MB_ICONSTOP);
Return;
}
// Construct two socket
CSocket ChatSend,server;
// Creat a SOCKET
if(!ChatSend.Create(nPort)) // nPort=1025
MessageBox("SendSocket create failed!", "Send",MB_ICONSTOP);
else{
// Associates a local address with the socket ChatSend.Bind(nProt,strAddr);
// strAddr="202.196.111.1"
// Start Listening
ChatSend.Listen();
// Creat a new socket and accepts a connection on the socket
ChatSend.Accept(Server);
}
// Send a CString
Server.SendTo(csSendText,csCounts,nPort,strAddr);
// Close the two socket
Server.Close();
ChatSend.Close();
(2)Client
// Socket initial
if(!AfxSocketInit())
{
MessageBox("WindowsSocket initial failed!", "Receive",MB_ICONSTOP);
return;
}
// Construct a socket
CSocket ChatRecieve;
// Creat a SOCKET
if(!ChatReceive.Create())
{
MessageBox("ReceiveSocket create
failed!","Receive",MB_ICONSTOP);
return;
}
else{
// Establishes a connection to a peer socket
ChatReceive.Connect(strAddr,nPort);
}
// Receive the CString
ChatReceive.ReceiveFrom(csReceiveText,csCounts,strAddr,nPort);
// Close the socket
ChatReceive.Close();
上述两个进程完成的工作是:由Server进程发送一字符串,Client 进程接收。strAddr 和 nPort 的含义与方法1中的相同csSendText 和 csReceiveText 为发送与接收的字符串;csCounts 为字串长度,这一长度在两个进程中要求接收长度小于或等于发送度,否则会导致数据传输错误。另外,在程序中要加入头文件afxsock.h,因为CSocket 类的有关说明均在afxsock.h中。
从上述两种方法中不难发现,方法1 适合于对多个不同类型数据的通信,方法2 适合 于对字符串的通信,具体选用何种方法则取决于具体应用的需求。