vs2013 MFC Socket UDP 简单聊天工具

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Dopamy_BusyMonkey/article/details/50057867

在一个解决方案中新建两个MFC对话框界面,两个界面都同时为客户端和服务器,代码内容除了 bind 绑定端口必须要绑定在不同的端口上,并且发送信息的端口两个界面互补对应。除此之外其他代码一样。

1、首先在对话框类添加一个成员函数,用于加载套接字库:

int CmfcchatDlg::IniSOCKDLL()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err = -1;

	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	return err;
}

2、再添加一个用于创建套接字和绑定端口的函数:

bool CmfcchatDlg::InitSocket()
{
	m_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (INVALID_SOCKET == m_socket)
	{
		AfxMessageBox(_T("套接字创建失败!"));
		return false;
	}
	SOCKADDR_IN addr;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addr.sin_family = AF_INET;
	addr.sin_port = htons(6000);
	int retval;
	retval = bind(m_socket, (SOCKADDR*)&addr, sizeof(SOCKADDR));
	if (SOCKET_ERROR == retval)
	{
		AfxMessageBox(_T("绑定失败!"));
		closesocket(m_socket);
		return false;
	}
	return true;
}

3、因为我们想要接收函数一直能接收数据,所以我们需要新开一个线程用来跑接收函数,如果想要把这个函数封装为对话框类的成员函数,就必须在把这个成员函数声明为静态成员函数,因为在线程创建的过程中所调用的接收数据的成员函数若不是静态成员函数,那么该成员函数就必须在类对象的基础上使用,但是由于程序开始时候并没有对象,所以线程并不知道这个接收函数属于哪个对象,也就无法使用这个成员函数,但是声明为静态变量之后,这个成员函数就不属于任何对象,而仅仅是属于这个类,这样线程在创建的时候就能使用这个静态的成员函数了。静态接收成员函数的声明和定义如下,必须满足MFC线程函数的格式:

static DWORD WINAPI RecvProc(LPVOID lpParameter);

DWORD WINAPI CmfcchatDlg::RecvProc(LPVOID lpParameter)
{
	SOCKET sock = ((RECVPARAM*)lpParameter)->sock;
	HWND hwnd = ((RECVPARAM*)lpParameter)->hwnd;
	delete lpParameter;
	SOCKADDR_IN addr;
	int len = sizeof(SOCKADDR);
	char recvBuf[200];
	char tempBuf[300];
	int retval;
	while (TRUE)
	{
		retval = recvfrom(sock, recvBuf, 200, 0, (SOCKADDR*)&addr, &len);
		if (SOCKET_ERROR == retval)
			break;
		sprintf_s(tempBuf, "%s说: %s", inet_ntoa(addr.sin_addr), recvBuf);
		::PostMessage(hwnd, WM_RECVDATA, 0, (LPARAM)tempBuf);
	}
	return 0;
}

4、上面涉及到一个结构体 RECVPARAM,因为在运行接收函数的时候,我们需要用到套接字(数据)和窗口句柄(用于将接收到的数据传递给窗口并显示),但是这个运行在线程里的静态接收函数只有一个输入参数,但是因为它是指针类型的输入参数,所以我们可以在对话框头文件中定义一个结构体,用来传递套接字和窗口句柄:

struct RECVPARAM
{
	SOCKET sock;
	HWND hwnd;
};

5、为了有更好的封装性,我们传递数据的套接字定义为私有变量,即在对话框类中定义一个私有的套接字变量:
private:
	SOCKET m_socket;

6、同时在静态接收函数中,我们需要将接受到的字符串数据传出给窗口控件并且显示,所以我们使用消息传递来做,这里为什么要这么做是因为在静态函数中无法使用非静态成员变量,而就算使用静态成员变量在编译的时候可能不会遇到问题,但是在链接的时候还是会出问题,所以在使用线程函数的时候要么用全局函数(封装性不好),要么就使用窗口句柄来传递。以下是消息响应函数,同样的格式一定也是要是这样的:
LRESULT CmfcchatDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
	CString str((char*)lParam);
	CString tmp;
	GetDlgItemText(IDC_EDIT_REC, tmp);
	str += "\r\n";
	str += tmp;
	SetDlgItemText(IDC_EDIT_REC, str);
	return true;
}
头文件函数声明:

afx_msg LRESULT OnRecvData(WPARAM wParam, LPARAM lParam);
头文件消息映射标识符宏定义:

#define WM_RECVDATA WM_USER+1
源文件中消息映射声明,一定要记得定义,否则编译连接运行可能都不会有异常,但是结果实现不了:

ON_MESSAGE(WM_RECVDATA, OnRecvData)

7、发送按钮响应函数,在初始化函数中可以看出,用于接收数据绑定的是6000端口,所以这里发送数据使用7000端口(因为另外一个窗口用于接收数据的绑定端口必须要跟6000不同):

void CmfcchatDlg::OnBnClickedBtnSend()
{
	// TODO:  在此添加控件通知处理程序代码
	DWORD dwIP;
	((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(7000);
	addr.sin_addr.s_addr = htonl(dwIP);
	CString str;
	GetDlgItemText(IDC_EDIT_SEND, str);
	sendto(m_socket, cs2ca(str), str.GetLength() + 1, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR));
	SetDlgItemText(IDC_EDIT_SEND, _T(""));
}

8、因为这里涉及 CString 到 char * 的转换,这里给出一个方便的函数,加在对话框成员函数中:

char* CmfcchatDlg::cs2ca(CString str)
{
	char *ptr;
#ifdef _UNICODE
	LONG len;
	len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
	ptr = new char[len + 1];
	memset(ptr, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, str, -1, ptr, len + 1, NULL, NULL);
#else
	ptr = new char[str.GetAllocLength() + 1];
	sprintf(ptr, _T("%s"), str);
#endif
	return ptr;
}

地址结构

struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址。在各种系统调用或者函数中,只要和网络地址打交道,就得用到这两个结构体。网络中的地址包含3个方面的属性:

1 地址类型: ipv4还是ipv6

2 ip地址

3 端口

include <netinet/in.h>  
struct sockaddr {  
    unsigned short    sa_family;    // 2 bytes address family, AF_xxx  
    char              sa_data[14];     // 14 bytes of protocol address  
};  
// IPv4 AF_INET sockets:  
struct sockaddr_in {  
    short            sin_family;       // 2 bytes e.g. AF_INET, AF_INET6  
    unsigned short   sin_port;    // 2 bytes e.g. htons(3490)  
    struct in_addr   sin_addr;     // 4 bytes see struct in_addr, below  
    char             sin_zero[8];     // 8 bytes zero this if you want to  
};  
struct in_addr {  
    unsigned long s_addr;          // 4 bytes load with inet_pton()  
}; 

注释中标明了属性的含义及其字节大小,这两个结构体一样大,都是16个字节,而且都有family属性,不同的是:sockaddr用其余14个字节来表示sa_data,而sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero分别表示端口、ip地址。sin_zero用来填充字节使sockaddr_in和sockaddr保持一样大小。
sockaddr和sockaddr_in包含的数据都是一样的,但他们在使用上有区别:程序员不应操作sockaddr,sockaddr是给操作系统用的程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。

转换函数

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)。


AF_INET(又称 PF_INET)

是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信。选择 AF_INET 的目的就是使用 IPv4 进行通信。因为 IPv4 使用 32 位地址,相比 IPv6 的 128 位来说,计算更快,便于用于局域网通信。而且 AF_INET 相比 AF_UNIX 更具通用性,因为 Windows 上有 AF_INET 而没有 AF_UNIX。

在使用udp 的  sendto  函数 和  recvfrom  函数的时候需要注意

前者必须指定地址,后者可以不指定地址(接收的地址为bing时候输入的地址),正常情况下一个网卡上应该除了自己的IP之外,还有回路地址 127.0.0.1 如果希望两个对话框分别绑定一个IP,然后互相发送,那么这里需要再添加一个专门用于发送数据的 SOCKET 私有变量。如果作此操作,因为现在绑定的是两个IP地址,所以接收和发送的端口号就算一样也是可以的。


如果在使用套接字函数的时候遇到为题,可以使用  WSAGetLastError() 函数(返回值为整型)来查看错误提示:

6 - WSA_INVALID_HANDLE
指定的事件对象无效。若使用与Win32函数对应的Winsock函数,便有可能产生这样的Win32错误。它表明传递给WSAWaitForMultipleEvents的一个句柄是无效的。
8 - WSA_NOT_ENOUGH_MEMORY
内存不够。这个Win32错误指出内存数量不足,无法完成指定的操作。
87 - WSA_INVALID_PARAMETER
一个或多个参数无效。这个Win32错误表明传递到函数内部的参数无效。假若事件计数参数无效,那么在执行WSAWaitForMultipleEvents的时候,也会发生这样的错误。
258 - WSA_WAIT_TIMEOUT
操作超时。这个Win32错误指出重叠I/O操作未在规定的时间内完成。
995 - WSA_OPERATION_ABORTED
重叠操作被取消。这个Win32错误指出由于套接字的关闭,造成一次重叠I/O操作的取消。
除此以外,该错误也可能在执行SIO_FLUSH这个I/O控制命令时出现。
996 - WSA_IO_INCOMPLETE
重叠I/O事件对象未处于传信状态。这个Win32错误也和重叠I/O操作密切相关,在调用WSAGetOverlappedResults函数的时候产生,指出重叠I/O操作尚未完成。
997 - WSA_IO_PENDING
重叠操作将在以后完成。用Winsock函数发出一次重叠I/O操作时,若出现这样的Win32错误,便表明操作尚未完成,而且会在以后的某个时间完成。
10004 - WSAEINTR
函数调用中断。该错误表明由于对WSACancelBlockingCall的调用,造成了一次调用被强行中断。
10009 - WSAEBADF
文件句柄错误。该错误表明提供的文件句柄无效。在MicrosoftWindowsCE下,socket函数可能返回这个错误,表明共享串口处于“忙”状态。
10013 - WSAEACCES
权限被拒。尝试对套接字进行操作,但被禁止。若试图在sendto或WSASendTo中使用一个广播地址,但是尚未用setsockopt和SO_BROADCAST这两个选项设置广播权限,便会产生这类错误。
10014 - WSAEFAULT
地址无效。传给Winsock函数的指针地址无效。若指定的缓冲区太小,也会产生这个错误。
10022 - WSAEINVAL
参数无效。指定了一个无效参数。例如,假如为WSAIoctl调用指定了一个无效控制代码,便会产生这个错误。另外,它也可能表明套接字当前的状态有错,例如在一个没有监听的套接字上调用accept或WSAAccept的时候。
10024 - WSAEMFILE
打开文件过多。提示打开的套接字太多了。通常,Microsoft提供者只受到系统内可用资源数量的限制。
10035 - WSAEWOULDBLOCK
资源暂时不可用。对非阻塞套接字来说,如果请求操作不能立即执行的话,通常会返回这个错误。比如说,在一个非阻塞套接字上调用connect,就会返回这个错误。因为连接请求不能立即执行。
10036 - WSAEINPROGRESS
操作正在进行中。当前正在执行非锁定操作。一般来说不会出现这个错误,除非正在开发16位Winsock应用程序。
10037 - WSAEALREADY
操作已完成。一般来说,在非锁定套接字上尝试已处于进程中的操作时,会产生这个错误。比如,在一个已处于连接进程的非锁定套接字上,再一次调用connect或WSAConnect。
另外,服务提供者处于执行回调函数(针对支持回调例程的Winsock函数)的进程中时也会出现这个错误。
10038 - WSAENOTSOCK
无效套接字上的套接字操作。任何一个把SOCKET句柄当作参数的Winsock函数都会返回这个错误。它表明提供的套接字句柄无效。
10039 - WSAEDESTADDRREQ
需要目标地址。这个错误表明没有提供具体地址。比方说,假如在调用sendto时,将目标地址设为INADDR_ANY(任意地址),便会返回这个错误。
10040 - WSAEMSGSIZE
消息过长。这个错误的含义很多。如果在一个数据报套接字上发送一条消息,这条消息
对内部缓冲区而言太大的话,就会产生这个错误。再比如,由于网络自身的限制,使一条消息过长,也会产生这个错误。最后,如果收到数据报之后,缓冲区太小,不能接收消息时,也会产生这个错误。
10041 - WSAEPROTOTYPE
套接字协议类型有误。在socket或WSASocket调用中指定的协议不支持指定的套接字类型。
比如,要求建立SOCK_STREAM类型的一个IP套接字,同时指定协议为IPPROTO_UDP,便会产生这样的错误。
10042 - WSAENOPROTOOPT
协议选项错误。表明在getsockopt或setsockopt调用中,指定的套接字选项或级别不明、未获支持或者无效。
10043 - WSAEPROTONOSUPPORT
不支持的协议。系统中没有安装请求的协议或没有相应的实施方案。比如,如果系统中没有安装TCP/IP,而试着建立TCP或UDP套接字时,就会产生这个错误。
10044 - WSAESOCKTNOSUPPORT
不支持的套接字类型。对指定的地址家族来说,没有相应的具体套接字类型支持。比如,在向一个不支持原始套接字的协议请求建立一个SOCK_RAW套接字类型时,就会产生这个错误。
10045 - WSAEOPNOTSUPP
不支持的操作。表明针对指定的对象,试图采取的操作未获支持。通常,如果试着在一
个不支持调用Winsock函数的套接字上调用了Winsock时,就会产生这个错误。比如,在一个数据报套接字上调用accept或WSAAccept函数时,就会产生这样的错误。
10046 - WSAEPFNOSUPPORT
不支持的协议家族。请求的协议家族不存在,或系统内尚未安装。多数情况下,这个错误可与WSAEAFNOSUPPORT互换(两者等价);后者出现得更为频繁。
10047 - WSAEAFNOSUPPORT
地址家族不支持请求的操作。对套接字类型不支持的操作来说,在试着执行它时,就会出现这个错误。比如,在类型为SOCK_STREAM的一个套接字上调用sendto或WSASendTo函数时,就会产生这个错误。另外,在调用socket或WSASocket函数的时候,若同时请求了一个无效的地址家族、套接字类型及协议组合,也会产生这个错误。
10048 - WSAEADDRINUSE
下地址正在使用。正常情况下,每个套接字只允许使用一个套接字地址(例如,一个IP套接字地址由本地IP地址及端口号组成)。这个错误一般和bind、connect和WSAConnect这三个函数有关。可在setsockopt函数中设置套接字选项SO_REUSEADDR,允许多个套接字访问同一个本地IP地址及端口号。
10049 - WSAEADDRNOTAVAIL
不能分配请求的地址。API调用中指定的地址对那个函数来说无效时,就会产生这样的错误。例如,若在bind调用中指定一个IP地址,但却没有对应的本地IP接口,便会产生这样的错误。另外,通过connect、WSAConnect、sendto、WSASendTo和WSAJoinLeaf这四个函数为准备连接的远程计算机指定端口0时,也会产生这样的错误。
10050 - WSAENETDOWN
网络断开。试图采取一项操作时,却发现网络连接中断。这可能是由于网络堆栈的错误,网络接口的故障,或者本地网络的问题造成的。
10051 - WSAENETUNREACH
网络不可抵达。试图采取一项操作时,却发现目标网络不可抵达(不可访问)。这意味着本地主机不知道如何抵达一个远程主机。换言之,目前没有已知的路由可抵达那个目标主机。
10052 - WSAENETRESET
网络重设时断开了连接。由于“保持活动”操作检测到一个错误,造成网络连接的中断。
若在一个已经无效的连接之上,通过setsockopt函数设置SO_KEEPALIVE选项,也会出现这样的错误。
10053 - WSAECONNABORTED
软件造成连接取消。由于软件错误,造成一个已经建立的连接被取消。典型情况下,这意味着连接是由于协议或超时错误而被取消的。
10054 - WSAECONNRESET
连接被对方重设。一个已经建立的连接被远程主机强行关闭。若远程主机上的进程异常中止运行(由于内存冲突或硬件故障),或者针对套接字执行了一次强行关闭,便会产生这样的错误。针对强行关闭的情况,可用SO_LINGER套接字选项和setsockopt来配置一个套接字。
10055 - WSAENOBUFS
没有缓冲区空间。由于系统缺少足够的缓冲区空间,请求的操作不能执行。
10056 - WSAEISCONN
套接字已经连接。表明在一个已建立连接的套接字上,试图再建立一个连接。要注意的是,数据报和数据流套接字均有可能出现这样的错误。使用数据报套接字时,假如事先已通过connect或WSAConnect调用,为数据报通信关联了一个端点的地址,那么以后试图再次调用sendto或WSASendTo,便会产生这样的错误。
10057 - WSAENOTCONN
套接字尚未连接。若在一个尚未建立连接的“面向连接”套接字上发出数据收发请求,便会产生这样的错误。
10058 - WSAESHUTDOWN
套接字关闭后不能发送。表明已通过对shutdown的一次调用,部分关闭了套接字,但事后又请求进行数据的收发操作。要注意的是,这种错误只会在已经关闭的那个数据流动方向上才会发生。举个例子来说,完成数据发送后,若调用shutdown,那么以后任何数据发送调用都会产生这样的错误。
10060 - WSAETIMEDOUT
连接超时。若发出了一个连接请求,但经过规定的时间,远程计算机仍未作出正确的响应(或根本没有任何响应),便会发生这样的错误。要想收到这样的错误,通常需要先在套接字上设置好SO_SNDTIMEO和SO_RCVTIMEO选项,然后调用connect及WSAConnect函数。
要想了解在套接字上设置SO_SNDTIMEO和SO_RCVTIMEO选项的详情,可参考第9章。
10061 - WSAECONNREFUSED
连接被拒。由于被目标机器拒绝,连接无法建立。这通常是由于在远程机器上,没有任何应用程序可在那个地址之上,为连接提供服务。
10064 - WSAEHOSTDOWN
主机关闭。这个错误指出由于目标主机关闭,造成操作失败。然而,应用程序此时更有可能收到的是一条WSAETIMEDOUT(连接超时)错误,因为对方关机的情况通常是在试图建立一个连接的时候发生的。
10065 - WSAEHOSTUNREACH
没有到主机的路由。应用程序试图访问一个不可抵达的主机。该错误类似于WSAENETUNREACH。
10067 - WSAEPROCLIM
进程过多。有些Winsock服务提供者对能够同时访问它们的进程数量进行了限制。
10091 - WSASYSNOTREADY
网络子系统不可用。调用WSAStartup时,若提供者不能正常工作(由于提供服务的基层系统不可用),便会返回这种错误。
10092 - WSAVERNOTSUPPORTED
Winsock.dll版本有误。表明不支持请求的Winsock提供者版本。
10093 - WSANOTINITIALISED
Winsock尚未初始化。尚未成功完成对WSAStartup的一次调用。
10101 - WSAEDISCON
正在从容关闭。这个错误是由WSARecv和WSARecvFrom返回的,指出远程主机已初始化了一次从容关闭操作。该错误是在像ATM这样的“面向消息”协议上发生的。
10102 - WSAENOMORE
找不到更多的记录。这个错误自WSALookupServiceNext函数返回,指出已经没有留下更多的记录。这个错误通常可与WSA_E_NO_MORE互换使用。在应用程序中,应同时检查这个错误以及WSA_E_NO_MORE。
10103 - WSAECANCELLED
操作被取消。这个错误指出当WSALookupServiceNext调用仍在处理期间,发出了对WSALookupServiceEnd(服务中止)的一个调用。此时,WSALookupServiceNext便会返回这个错误。这个错误代码可与WSA_E_CANCELLED互换使用。作为应用程序,应同时检查这个错误以及WSA_E_CANCELLED
10105 - WSAEINVALIDPROVIDER
无效的服务提供者。这个错误同服务提供者关联在一起,在提供者不能建立正确的Winsock版本,从而无法正常工作的前提下产生。
10106 - WSAEPROVIDERFAILEDINIT
提供者初始化失败。这个错误同服务提供者关联在一起,通常见于提供者不能载入需要的DLL时。
10107 - WSASYSCALLFAILURE
系统调用失败。表明绝对不应失败的一个系统调用却令人遗憾地失败了。
10108 - WSASERVICE_NOT_FOUND
找不到这样的服务。这个错误通常与注册和名字解析函数相关,在查询服务时产生(第10章对这些函数进行了详尽解释)。该错误表明,在给定的名字空间内,找不到请求的服务。
10109 - WSATYPE_NOT_FOUND
找不到类的类型。该错误也与注册及名字解析函数关联在一起,在处理服务类(Service Class)时发生。若注册好一个服务的实例,它必须引用一个以前通过WSAInstallServiceClass安装好的服务。
10110 - WSA_E_NO_MORE
找不到更多的记录。这个错误是自WSALookupServiceNext调用返回的,指出已经没有剩
下的记录。该错误通常可与WSAENOMORE互换使用。作为一个应用程序,应同时检查这个
错误以及WSAENOMORE。
10111 - WSA_E_CANCELLED
操作被取消。该错误指出在对WSALookupServiceNext的调用尚未完成的时候,又发出了对WSALookupServiceEnd(中止服务)的一个调用。这样,WSALookupServiceNext就会返回该错误。这个错误代码可与WSAECANCELLED互换使用。作为一个应用程序,应同时检查这个错误以及WSAECANCELLED。
10112 - WSAEREFUSED
查询被拒。由于被主动拒绝,所以一个数据库查询操作失败。
11001 - WSAHOST_NOT_FOUND
主机没有找到。这个错误是在调用gethostbyname和gethostbyaddr时产生的,表明没有找到一个授权应答主机(AuthoritativeAnswerHost)。
11002 - WSATRY_AGAIN
非授权主机没有找到。这个错误也是在调用gethostbyname和gethostbyaddr时产生的,表明没有找到一个非授权主机,或者遇到了服务器故障。
11003 - WSANO_RECOVERY
遇到一个不可恢复的错误。这个错误也是在调用gethostbyname和gethostbyaddr时产生的,指出遇到一个不可恢复的错误,应再次尝试操作。
11004 - WSANO_DATA
没有找到请求类型的数据记录。这个错误也是在调用gethostbyname和gethostbyaddr时产生的,指出尽管提供的名字有效,但却没有找到与请求类型对应的数据记录。
11005 - WSA_QOS_RECEIVERS
至少有一条预约消息抵达。这个值同IP服务质量(QoS)有着密切的关系,其实并不是一个真正的“错误”(QoS的详情见第12章)。它指出网络上至少有一个进程希望接收QoS通信。
11006 - WSA_QOS_SENDERS
至少有一条路径消息抵达。这个值同QoS关联在一起,其实更像一种状态报告消息。它指出在网络上,至少有一个进程希望进行QoS数据的发送。
11007 - WSA_QOS_NO_SENDERS
没有QoS发送者。这个值同QoS关联在一起,指出不再有任何进程对QoS数据的发送有兴趣。请参阅第12章,了解在发生这样的错误时,对所发生情况的一系列完整说明。
11008 - WSA_QOS_NO_RECEIVERS
没有QoS接收者。这个值同QoS关联在一起,指出不再有任何进程对QoS数据的接收有兴趣。请参阅第12章,查阅对这个错误的完整说明。
11009 - WSA_QOS_REQUEST_CONFIRMED
预约请求已被确认。QoS应用可事先发出请求,希望在批准了自己对网络带宽的预约请求后,收到通知。若发出了这样的请求,一旦批准,便会收到这样的消息。请参阅第12章,了解对此消息的详细说明。
11010 - WSA_QOS_ADMISSION_FAILURE
缺乏资源致错。资源不够,以至于无法满足QoS带宽请求。
11011 - WSA_QOS_POLICY_FAILURE
证书无效。表明发出QoS预约请求的时候,要么用户并不具备正确的权限,要么提供的证书无效。
11012 - WSA_QOS_BAD_STYLE
未知或冲突的样式。QoS应用程序可针对一个指定的会话,建立不同的过滤器样式。若出现这一错误,表明指定的样式类型要么未知,要么存在冲突。请参阅第12章,了解对过滤器样式的详细说明。
11013 - WSA_QOS_BAD_OBJECT
无效的FILTERSPEC结构或者提供者特有对象。假如为QoS对象提供的FILTERSPEC结构无效,或者提供者特有的缓冲区无效,便会返回这样的错误,详见第12章。
11014 - WSA_QOS_TRAFFIC_CTRL_ERROR
FLOWSPEC有问题。假如通信控制组件发现指定的FLOWSPEC参数存在问题(作为QoS对象的一个成员传递),便会返回这样的错误。
11015 - WSA_QOS_GENERIC_ERROR
常规QoS错误。这是一个比较泛泛的错误;假如其他QoS错误都不适合,便返回这个错误。


阅读更多

扫码向博主提问

BusyMonkey

没人能阻挡你,除了你自己
  • 擅长领域:
  • java
  • 图像处理
  • js
  • ios
  • python
去开通我的Chat快问
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页