首页 > 技术文章 > c++游戏编程入门1 网络编程基础(CAsyncSocket类和CSocket类)

ccsuCBG 2018-11-04 14:07 原文

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

推荐阅读