MFC 通信简介
互联网通信基础是 TCP/IP,即传输控制协议和网络互连协议。在 TCP/IP 中计算机软件通信必须依赖于通信端口,端口号的范围是 0 ~ 65535。每个进程启动后可以申请一个或多个端口号,但在一台计算机内每个端口号同时只能被一个进程占用,否则就会造成端口冲突。
MFC 套接字简介
1.MFC 中与套接字(socket)功能有关的类包括
CAsyncSocket 类 | 对套接字 API 进行了较低级别的封装 |
CSocket 类 | 对套接字 API 进行了较高级别的封装 |
其中:CSocket 类是 CAsyncSocket 类的派生类
2.套接字种类
流套接字(Stream Socket)
(1)使用 TCP协议进行通信
具有 TCP 协议所拥有的各种特征,面向连接的、可靠的数据流传输服务。数据包不会出现丢失、重复、乱序等现象
(2)数据报套接字(datagram socket)
使用 UDP 协议进行通信,具有 UDP 协议所拥有的各种特征。面向非连接的、不可靠的用户数据报传输服务,数据包可能出现丢失、重复、乱序等现象。
3.套接字类函数
create:用于创建一个 Windows 套接字,并将其附加到 CAsyncSocket 类对象上
BOOL Create(UINT nSocketPort = 0,
int nSocketType = SOCK_STREAM,
long IEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL
);
参数说明如下:
-
nSocketPort
表示套接字端口,如果为 0,系统将自动选择一个端口 -
nSocketType
表示套接字的类型,SOCK_STREAM表示流套接字SOCK_DGRAM表示数据报套接字。 -
lEvent
一个位掩码,指定应用程序能够处理的网络事件的组合。-
FD_READ 想要收到阅读准备的通知。
-
FD_WRITE 想要收到写作准备的通知。
-
FD_OOB 想要接收带外数据到达的通知。
-
FD_ACCEPT 想要接收传入连接的通知。
-
FD_CONNECT 想要接收已完成连接的通知。
-
FD_CLOSE 想要接收套接字关闭的通知。
-
-
lpszSockAddress
指向已连接套接字的网络地址的字符串的指针,虚线数字如“128.56.22.8” 。为此参数传递NULL字符串表示CAsyncSocket实例应在所有网络接口上侦听客户端活动。
GetLastError:用于获取最后一次操作失败的状态信息
static int GetLastError();
GetPeerName:用于获取套接字连接的 IP 地址信息。
BOOL GetPeerName(CString& rPeerAddress, UINT& rPeerPort);
BOOL GetPeerName(SOCKADDR* lpSockAddr, int* lpSCokAddrLen);
参数说明如下:
-
rPeerAddress
对接收函数返回IP地址的CString对象的引用。 -
rPeerPort
用于记录端口号。 -
lpSockAddr
指向SOCKADDR结构的指针,该结构接收对等套接字的名称。 -
lpSockAddrLen
指向lpSockAddr中地址长度的指针,以字节为单位。返回时,lpSockAddrLen参数包含以字节为单位返回的lpSockAddr的实际大小。
Accept:用于接收客户端的链接
virtual BOOL Accept(
CAsyncSocket& rConnectedSocket,
SOCKADDR* lpSockAddr = NULL,
int* lpSockAddrLen = NULL
);
参数说明如下:
-
rConnectedSocket
标识可用于连接的新套接字的引用。 -
lpSockAddr
指向SOCKADDR结构的指针,该结构接收连接套接字的地址,如网络上已知的那样。lpSockAddr参数的确切格式由创建套接字时建立的地址族决定。如果lpSockAddr和/或lpSockAddrLen等于NULL,则不返回有关已接受套接字的远程地址的信息。 -
lpSockAddrLen
指向lpSockAddr中地址长度的指针,以字节为单位。lpSockAddrLen是一个value-result参数:它应该最初包含lpSockAddr指向的空间量; 返回时,它将包含返回地址的实际长度(以字节为单位)。
Bind:用于将 IP 地址和端口号绑定到套接字上
BOOL Bind(
UINT nSocketPort,
LPCTSTR lpszSocketAddress = NULL
);
BOOL Bind (
const SOCKADDR* lpSockAddr,
int nSockAddrLen
);
参数说明如下:
-
nSocketPort
标识套接字应用程序的端口。 -
lpszSocketAddress
网络地址,点缀数如“128.56.22.8”。传递此参数的NULL字符串表示CAsyncSocket实例应侦听所有网络接口上的客户端活动。 -
lpSockAddr
指向SOCKADDR结构的指针,该结构包含要分配给此套接字的地址。 -
nSockAddrLen
lpSockAddr中地址的长度(以字节为单位)。
connect:用于发送一个链接请求
BOOL Connect(
LPCTSTR lpszHostAddress,
UINT nHostPort
);
BOOL Connect(
const SOCKADDR* lpSockAddr,
int nSockAddrLen
);
参数说明如下:
-
lpszHostAddress
此对象所连接的套接字的网络地址:计算机名称,例如“ftp.microsoft.com”,或点号,例如“128.56.22.8”。 -
nHostPort
标识套接字应用程序的端口。 -
lpSockAddr
指向SOCKADDR结构的指针,该结构包含已连接套接字的地址。 -
nSockAddrLen
lpSockAddr中地址的长度(以字节为单位)。
close:用于关闭套接字
virtual void Close( );
listen:用于将套接字置于监听模式
BOOL Listen(
int nConnectionBacklog = 5
);
- nConnectionBacklog
挂起连接队列可以增长的最大长度。有效范围是1到5。
receive:用于在流式套接字中接收数据
virtual int Receive(
void* lpBuf,
int nBufLen,
int nFlags = 0
);
-
lpBuf
传入数据的缓冲区。 -
nBufLen lpBuf
的长度,以字节为单位。 -
nFlags
指定进行调用的方式。此函数的语义由套接字选项和nFlags参数确定。后者是通过将以下任何值与C ++ OR运算符组合而构造的:-
MSG_PEEK 查看传入的数据。数据将复制到缓冲区中,但不会从输入队列中删除。
-
MSG_OOB 处理带外数据。
-
send:用于向流式套接字中发送数据
virtual int Send(
const void* lpBuf,
int nBufLen,
int nFlags = 0
);
-
lpBuf
包含要传输的数据的缓冲区。 -
nBufLen lpBuf
中的数据长度,以字节为单位。 -
nFlags
指定进行调用的方式。此函数的语义由套接字选项和nFlags参数确定。后者是通过将以下任何值与C ++ OR运算符组合而构造的:-
MSG_DONTROUTE 指定数据不应受路由限制。Windows套接字供应商可以选择忽略此标志。
-
MSG_OOB 发送带外数据(仅限SOCK_STREAM)。
-
4.套接字事件响应
OnAccept:当套接字接收链接请求时触发该事件(服务器端)
virtual void OnAccept(
int nErrorCode
);
-
nErrorCode
套接字上的最新错误。以下错误代码适用于OnAccept成员函数:-
0 功能执行成功。
-
WSAENETDOWN Windows Sockets实现检测到网络子系统发生故障。
-
OnClose:当套接字关闭时触发该事件
virtual void OnClose(
int nErrorCode
);
-
nErrorCode
套接字上的最新错误。以下错误代码适用于OnCLose成员函数:-
0 功能执行成功。
-
WSAENETDOWN Windows Sockets实现检测到网络子系统发生故障。
-
WSAECONNRESET 远程端重置了连接。
-
WSAECONNABORTED 由于超时或其他故障导致连接中止。
-
OnConnect:当套接字连接之后触发该事件(客户端)
virtual void OnConnect(
int nErrorCode
);
-
nErrorCode
套接字上的最新错误。以下错误代码适用于OnCnnect成员函数:-
0 功能执行成功。
-
WSAEADDRINUSE 指定的地址已被使用。
-
WSAEADDRNOTAVAIL 指定的地址在本地计算机上不可用。
-
WSAEAFNOSUPPORT 指定系列中的地址不能与此套接字一起使用。
-
WSAECONNREFUSED 强行拒绝连接尝试。
-
WSAEDESTADDRREQ 需要目标地址。
-
WSAEFAULT lpSockAddrLen参数不正确。
-
WSAEINVAL 套接字已绑定到某个地址。
-
WSAEISCONN 套接字已连接。
-
WSAEMFILE 没有更多文件描述符可用。
-
WSAENETUNREACH 此时无法从此主机访问网络。
-
WSAENOBUFS 没有可用的缓冲区空间。插座无法连接。
-
WSAENOTCONN 套接字未连接。
-
WSAENOTSOCK 描述符是一个文件,而不是套接字。
-
WSAETIMEDOUT 尝试在没有建立连接的情况下连接超时。
-
OnReceive:当套接字上有数据被接收时触发该事件
virtual void OnReceive(
int nErrorCode
);
-
nErrorCode
套接字上的最新错误。以下错误代码适用于OnReceive成员函数:-
0 功能执行成功。
-
WSAENETDOWN Windows Sockets实现检测到网络子系统发生故障。
-
OnSend:当套接字发送数据时触发该消息
virtual void OnSend(
int nErrorCode
);
-
nErrorCode
套接字上的最新错误。以下错误代码适用于OnSend成员函数:-
0 功能执行成功。
-
WSAENETDOWN Windows Sockets实现检测到网络子系统发生故障。
-
更多详细解释请参考 MSDN : https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/09353w3t(v%3dvs.90)
MFC 通信
1.通信前的准备
①客户端调用 connect 函数以连接到服务器
②服务器端调用 listen 函数以监听客户的进入
③服务器端调用 accept 函数与客户建立连接
2.收发数据
流套接字发送数据:Send
流套接字接收数据:Receive
3.C/S模型
遇到的问题:
1.客户端无法连接服务器
答:
①检查服务器是否正常运行
②客户端IP 和端口是否配置正常,是否和服务器 IP 和端口一致
③在IP 和端口配置正确情况下,考虑错误发生在跨网段通信。
首先 cmd 打开控制台,ping 服务器的 IP 地址,如果 ping通则说明问题不在此,如果没 ping 通则问题出在此处,需要将两台电脑 IP 运行在同一网段上。
④分别在服务器端accept 和客户端 connect 设置断点,检查错误发生在服务器端还是客户端。如果发生在 connect 处,则调用WSAGetLastError函数:https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-wsagetlasterror#syntax (这个链接里有详细用法及错误返回码解释)