c++游戏编程入门1 网络编程基础(CAsyncSocket类和CSocket类)
CAsyncSocket类和CSocket类
1.CAsyncSocket类和Socket类的介绍
MFC中把复杂的Winsock API函数封装在CAsyncSocket类中,使得CAsyncSocket提供了基于异步通信的套接字服务,CSokcet类是由CAsyncSocket类继承下来的,其提供了比CAsyncSocket更高层的WinSock API接口,例如,CSocket类可以将套接字上发送和接收的数据和一个文件对象(CSocketFile类)关联起来,通过读写文件来达到发送和接收数据的目的。CSocket类还可以和CArchive类一起合作来管理发送和接收的数据,这使得管理数据收发更加便利。
2.创建CAsyncSocket对象 Creat()
函数原型:
BOOL CAsyncSocket::Create( UINT nSocketPort = 0,//自动分配一个端口号 int nSocketType = SOCK_STREAM, //TCP连接 long lEvent = FD_READ | FD_WRITE | FD_OOB |FD_ACCEPT |FD_CONNECT |FD_CLOSE, LPCTSTR lpszSocketAddress =NULL //本地IP地址(可以使用分点法或者域名来表示) )
可以通过指明lEvent所包含的标记来确定需要异步处理的事件,对于指明的相关事件的相关函数调用不需要等待完成后再返回,函数会马上返回,然后在完成任务后发送事件通知,并利用重载一下成员成员来处理各种网络事件。
参数值 | 事件 | 重载的函数 |
---|---|---|
FD_READ | 有数据到达 | void OnReceive(int nErrorCode) |
FD_WRITE | 有数据发送 | void OnSend(int nErrorCode) |
FD_OOB | 收到外带数据 | void OnOutOfBandData(int nErrorCode) |
FD_ACCEPT | 服务器端等待连接成功 | void OnAccept(int nErrorCode) |
FD_CONNECT | 客户端连接成功 | void OnConnect(int nErrorCode) |
FD_CLOSE | 套接字关闭 | void OnClose(int nErrorCode) |
在重载函数被调用时,其参数nErrorCode会被设置一个值。当这个值为0时,表示正常完成;如果非零时,表示有错误,通过CAsyncSocket的 成员函数GetLastError()得到相应的错误值
3.绑定端口
BOOL CAsyncSocket::Bind()( UINT nSocketPort =0, //自动分配一个端口号 LPCTSTR lpszSocketAddress =NULL //本地IP地址 )
4.监听端口
BOOL CAsyncSocket::Listen( int nConnectionBacklog = 5 //最大同时连接数 )
5.接收连接
BOOL CAsyncSocket::Accept( CAsyncSocket& rConnectedSocket, //连接套接字 SOCKADDR * lpSockAddr =NULL, //存放提出连接请求服务的主机的信息(客户端),如果为空表示调用者不需要知道 int * lpSockAddrLen =NULL //表示SOCKADDR地址结构长度 )
6.连接服务器端口
BOOL CAsyncSocket::Connect( LPCTSTR lpszSocketAddress, //服务器IP地址 UINT nHostPort //服务器端口号 )
7.发送数据
1)面向连接(TCP)
int CAsyncSocket::Send( const void * lpBuf, //指向需要发送数据的存储区首地址 int nBufLen, //需要发送数据的长度 int nFlags =0 //一般设置为0 )
2) 无连接(UDP)
int CAsyncSocket::SendTo( const void * lpBuf, //指向需要发送数据的存储区首地址 int nBufLen, //需发送数据的长度 UINT nHostPort, //目的主机端口 LPCTSTR lpszHostAddress = NULL, //目的主机地址 int nFlags =0 //一般设置为0 )
函数返回值为已经发送的数据长度。当为-1时,可以通过CAsyncSocket的成员函数GetLastError()得到相应的错误值
8.接收数据
1)面向连接(TCP)
int CAsyncSocket::Receive( const void * lpBuf, //指向接收数据的存储缓冲区指针 int nBufLen, //存储缓冲区的最大长度 int nFlags =0 //一般设置为0 )
2)无连接(UDP)
int CAsyncSocket::ReceiveFrom( const void * lpBuf, //指向接收数据的存储缓冲区地址 int nBufLen, //接收缓冲区最大长度 CString &rSocketAddress, //发送数据的源主机地址 UINT &rSocketPort, //发送数据的源主机端口 int nFlags=0 //一般设置为0 )
返回值为已经接收到的数据长度,当为-1时,可以通过CAsyncSocket的成员函数GetLastError()得到相应的错误值
9.关闭端口
当通信结束时,需要调用Close成员函数来关闭连接端口
BOOL CAsyncSocket::Close()
10.CSocket类
由于CSocket是从CAsyncSocket类派生的,所以其拥有CAsyncSocket类的所有公共成员函数和功能。只要注意,要创建CSocket的对象时,只能调用CSocket类的创建函数。
函数原型:
BOOL CAsyncSocket::Create( UINT nSocketPort =0, //自动分配端口号 int nSocketType =SOCK_STREAM, //TCP连接 LPCTSTR lpszSocketAddress =NULL //本地IP地址 )
这样创建出来的套接字,是不支持异步处理机制的(非阻塞模式)的,所有成员函数的调用都必须完成后才能返回给调用者
CAsyncSocket和CSocket类的编程模型
1.CAsyncSocket类的编程模型
在一个MFC应用程序中,要想轻松处理多个网络协议,而又不失灵活性时,可以考虑使用CAsyncSocket类,其效率比CSocket类更高
编程模型流程
1.创建一个CAsyncSocket对象,并用这个对象的Create成员函数产生一个Socket句柄
1使用默认参数参数一个字节流套接字
CAsyncSocket sock;
sock.create();
2)在指定端口号上产生一个数据报套接字 CAsyncSocket *pSocket =new CAsyncSocket(); int nPort =80; pSocket->create(nPort,SOCK_DGRAM);
上面第一种方法是在栈上产生一个CAsyncSocket对象,而第二种方法是在堆上产生一个CAsyncSocket对象;
第一种方法中Create成员函数用默认参数产生一个字节流套接字,第二种方法中用Create成员函数在指定端口上产生一个数据报套接字
2.如是客户端程序,用CAsyncSocket::Connect成员函数连接到服务端; 如是服务端程序,用CAsyncSocket::Bind成员函数绑定端口,然后用CAsyncSocket::Listen成员函数开始监听,一旦收到连接消息,则调用 CAsyncSocket::Accept成员函数开始接受。
3.调用其他的CAsyncSocket类的Receive、ReceiveFrom、Send、SendTo等成员函数进行通信
4.通信结束后,销毁CAsyncSocket对象,如果是在栈上产生的CAsyncSocket对象,则对象超出定义的范围时自动被析构;如果是在堆上产生,也就是用了new这个操作符,则必须使用delete操作符销毁CAsyncSocket对象
2.CSocket类编程模型
使用CSocket对象涉及CArchive和CSocketFile类对象
编程模型流程
1.构造一个CSocket对象
2.使用这个对象的Create成员函数产生socket对象,在客户端,除非需要数据报套接字,Create()函数一般情况下应该使用默认参数。而对于服务端,必须在调用Create时指定一个端口
3.如果是客服端套接字,则调用CAsyncSocket的成员函数Connect()与服务方套接字连接; 如果是服务端套接字,则调用Listen()开始监听来自客户端的连接请求,收到连接请求后,调用Accept()函数接收请求,建立连接。请注意Accept成员函数需要一个新的并且为空的CSocket对象作为其参数
4.产生一个CSocketFile对象,并把其与CSocket对象关联起来
5.为接收和发送数据各产生一个CArchive对象,把其与CSocketFile对象关联起来,切记CArchive是不能和数据报套接字一起工作的
6.使用CArchive对象的Read()、Write()等函数在客户端与服务端之间传送数据
7.通信完毕后,销毁CArchive、CSocketFile和CSocket对象
2018-11-04