Windows Embedded Compact 7网络编程概述(上)

     现在,不管是嵌入式设备、PDA仍是智能手机,网络都是必不可少的模块。网络令人们更方便地共享设备上的信息和资源。并且,利用智能手机浏览互联网,也逐渐成为生活中的常见手段。物联网所倡导的物物相联,也离不开设备中的网络。所以,熟练掌握网络编程技术,是Windows CE开发的基本技能。跟以前Windows CE的版本以及其余的Windows系统同样,Windows Embedded CE 7的网络编程也是基于套接字来实现的。程序员

本章首先将介绍套接字的相关原理和编程基础,而后介绍几种套接字的实际应用,包括了Ping编程、RAS编程,以及最经常使用的UDP编程和TCP编程。编程

11.1 套接字编程基础

Windows Socket Winsock)是Windows CE网络编程的基础。Winsock是基于U.C. Berkeley大学开发的套接字接口,定义的一套Windows环境下通用的网络编程接口。Winsock不只支持了对多种传统传输协议如TCPUDP等协议的访问,也已经可以支持IPv6等新的协议。相应地,应用程序能够建立多种类型的套接字,知足不一样网络环境和特定需求下的网络链接。另外,Winsock包含了一组针对Windows的扩展库函数,便于程序员利用Windows的消息驱动机制。缓存

Winsock提供的不是协议,而是与协议无关的交互规范或是接口。这个接口能充分发挥底层传输协议的通讯特性。因为Winsock不是协议,它不会改变物理传输线路上的信号。服务器

Windows的开发系统架构框架(WOSA)下,WinsockAPI和协议栈之间定义了一套标准的服务提供接口(SPI)。程序员或是网络软件供应商能够利用SPI实现一个分层服务提供商(LSP,来建立新的传输服务提供商或是扩展示有的传输服务提供商。网络

Winsock接口的目的在于为程序员提供一套简单的API,并让各网络软件供应商共同遵照。此外,Winsock还定义了一个二进制接口(ABI),保证利用了Winsock API的应用程序可以在全部符合Winsock规范但属于不一样网络软件供应商的平台上运行。架构

从代码的角度上看,Winsock就是实现了一套库函数调用,以及相关的语义。从功能层次上看,Winsock向上为应用程序提供了能够调用的API,实现不一样网络中应用程序间的通信;向下经过操控网络传输协议,完成网络间数据的传输和通讯。它们的关系如图11.1所示。框架

Winsock在不一样的Windows系统中,提供的API稍有差别。下面将具体介绍Windows Embedded CE环境下提供的Winsock API异步

11.1.1 Winsock初始化和释放

在应用程序调用Winsock提供的API以前,相应版本的Winsock动态库必须加载进来。若是在没有初始化Winsock的状况下而直接调用Winsock中的函数,将会返回错误SOCKET_ERRORsocket

WSAStartup函数是初始化Winsock的函数,它的原型以下:ide

int WSAStartup(

  WORD wVersionRequested,

  LPWSADATA lpWSAData

);

函数的返回值为0,表示函数执行正确。不然,函数执行失败。下面是函数返回的错误码及其相应的描述。,如表11.1所示

错误码

描述

WSASYSNOTREADY

底层的网络子系统没有准备好进行网络通讯

WSAVERNOTSUPPORTED

请求Winsock的版本不被现有的Winsock实现所支持

WSAEPROCLIM

请求的任务数已达上限

WSAEFAULT

lpWSAData结构体不合法

        表11.1错误码及描述

参数wVersionRequested指定须要加载的Winsock动态库的版本。Winsock库的主版本由低位字节指定,而副版本由高位字节指定。

参数lpWSAData是一个指向WSADATA结构体的指针,用于存储Winsock的具体实现细节。WSADATA结构体的声明以下:

typedef struct WSAData {

  WORD wVersion;

  WORD wHighVersion;

  char szDescription[WSADESCRIPTION_LEN+1];

  char szSystemStatus[WSASYS_STATUS_LEN+1];

  unsigned short iMaxSockets;

  unsigned short iMaxUdpDg;

  char FAR* lpVendorInfo;

} WSADATA, *LPWSADATA;

wVersion域表示Winsock动态库指望用户使用的版本。

wHighVersion域是Winsock动态库所能容乃的最高版本。通常而言,这个域的值与wVersion相同。

szDescription域保存了Winsock动态库对其实现的描述。这个域最可能用于在状态消息中打印。

szSystemStatus域存储的是Winsock动态库的相关状态或是配置信息。

iMaxSockets域表示同时最多能打开的套接字的数目。它为了向后兼容而保留。不过在Winsock 2.0及之后的版本中,这个域将被忽略。

iMaxUdpDg域表示同时最多能打开的报文的数目。在Winsock 2.0及之后的版本中,它被忽略。

lpVendorInfo域是为Winsock具体实现的厂商信息预留的。在Winsock 2.0及之后的版本中,它也被忽略。

应用程序在调用完Winsock后,须要调用WSACleanup函数来释放已分配的资源。WSACleanup函数的原型以下:

int WSACleanup (void);

若是没有出错,函数返回值为0。不然,函数返回的错误码以及对应的描述如表11.2所示:

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用WSACleanup函数

WSAENETDOWN

网络子系统出错

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

           表11.2函数错误码返回以及对应描述

下列示例程序的功能是应用程序只加载版本号为2.2Winsock动态库。

WORD wVersionRequested;

WSADATA wsaData;

int err;

 

wVersionRequested = MAKEWORD( 2, 2 );

 

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 ) {

    /* Tell the user that we could not find a usable */

    /* WinSock DLL.                                  */

    return;

}

 

/* Confirm that the WinSock DLL supports 2.2.*/

/* Note that if the DLL supports versions later    */

/* than 2.2 in addition to 2.2, it will still return */

/* 2.2 in wVersion since that is the version we      */

/* requested.                                        */

 

if ( LOBYTE( wsaData.wVersion ) != 2 ||

        HIBYTE( wsaData.wVersion ) != 2 ) {

    /* Tell the user that we could not find a usable */

    /* WinSock DLL.                                  */

    WSACleanup( );

    return; 

}

11.1.2 建立套接字

函数socket用于为程序建立一个套接字。函数的原型以下:

SOCKET socket(

  int af,

  int type,

  int protocol

);

参数af指定了通信家庭地址,常见的是AF_INET

参数type指定了套接字的类型。在Winsock 1.1版本中,只有SOCK_STREAMSOCK_DGRAM两种类型。SOCK_STREAM类型的套接字支持有序的、可靠的、双向的、基于链接的,且支持带外数据的数据传输机制。它利用TCP协议完成数据的传输。SOCK_DGRAM类型的套接字利用数据包进行传输,是无序的、不可靠的协议。它利用UDP协议传输数据。Winsock 2.2版本增长了许多新的套接字协议。程序可以经过函数WSAEnumProtocols动态发现全部能被支持的套接字类型。参数protocol指定了协议的类型,包括IPICMPTCPUDP等协议。

函数若是执行成功,则返回此套接字的句柄。不然,返回值为INVALID_SOCKET。经过调用WSAGetLastError函数,程序员能够查看对应的错误码。可能错误码的描述以下:如表11.3所示。

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEAFNOSUPPORT

指定的通信家庭地址不被支持

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEMFILE

没有套接字描述符可用

WSAENOBUFS

没有缓存空间供套接字使用

WSAEPROTONOSUPPORT

指定的协议不被支持

WSAEPROTOTYPE

指定的协议与套接字类型不兼容

WSAESOCKTNOSUPPORT

通信家庭地址不支持指定的套接字类型

11.3错误码以及描述

11.1.3 关闭套接字

函数closesocket用来关闭现有的套接字。它的原型以下:

int closesocket(

  SOCKET s

);

参数s指定要关闭套接字的句柄。

若是函数执行成功,则返回值为0。不然,能够调用WSAGetLastError函数查看具体的错误信息。可能的错误信息如表11.3所示:

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAENOTSOCK

参数不是一个正确的套接字句柄

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEINTR

套接字已经被关闭

WSAEWOULDBLOCK

套接字被设置为不能阻塞状态

      表11.3套接字错误码与描述

函数closesocket将释放套接字相关的全部资源,包括了相关的命名信息,以及发送或接受队列中的数据。同时,当前进程中的异步调用以及等待中的阻塞操做都没取消,并且不会发出通知消息。此外,处于等待状态的发送和接受操做也被取消,可是已经完成的操做会继续执行。

为了不函数closesocket操做的数据或操做的丢失,程序应先调用函数shutdown从容中断链接。所谓“从容中断链接“是为了保证通讯方可以收到程序发出的全部数据,应该通知接收端再也不发送数据,一样地,通讯方也应该如此。函数shutdown的原型以下:

int shutdown(

  SOCKET s,

  int how

);

参数s指定了待关闭的套接字句柄。

参数how表示要中断的操做类型。可选的类型以及相应的描述如表11.4所示:

错误码

描述

SD_RECEIVE

不容许调用recv函数。对于TCP套接字来讲,不论是数据在等待接收,仍是数据接连到达,都要重设链接。对于UDP套接字来讲,到达的数据包仍然会被接收并加入到数据队列中。

SD_SEND

不容许调用send函数。对于TCP套接字来讲,在当前的数据被所有发送出去且收到接收者的确认后,发出FIN信号。

SD_BOTH

不容许调用recv函数以及send函数

            表11.4中断操做类型错误码与描述

函数执行成功会返回0;不然,表示出错。此时,函数WSAGetLastError能返回的错误码以及相应的描述如表11.5所示:

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEINVAL

参数how不合法或是与当前的套接字类型不一致。

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAENOTCONN

套接字链接不通

WSAENOTSOCK

参数不是一个正确的套接字句柄

11.5函数WSAGetLastError能返回的错误码与描述

11.1.4 绑定套接字

函数bind的功能在于将一个网络地址与套接字绑定。函数bind的原型以下:

int bind(

  SOCKET s,

  const struct SOCK_ADDR* name,

  int namelen

);

参数s指定待绑定的套接字。

参数name是指定sockaddr结构的地址,指定了要绑定的地址。若是没有指定的地址,则参数被设置为ADDR_ANY。例如在服务器端的代码中,能够接受任意地址的客户端请求,此时参数name被设置为ADDR_ANY

参数namelen指定了参数name的大小。

name域须要的值是一个网络地址,主要包括如下几个部分:

1) 地址家族

2) 主机地址

3) 端口号

结构体sockaddrsockaddr_in就是包括了以上三个部分的结构体。它们的声明以下:

struct sockaddr {

        ushort  sa_family;

        char    sa_data[14];

};

struct sockaddr_in {

        short   sin_family;

        u_short sin_port;

        struct  in_addr sin_addr;

        char    sin_zero[8];

};

这两个结构体的大小同样,只是sockaddr_in结构体的描述更加详细。下面对sockaddr_in结构体的成员做简单的介绍。

sin_family域只能是AF_INET,表示Winsock正是用IP地址家族。

sin_port域指定了通信的端口。在底层协议的实现中,有一部分端口有特定的用途,例如FTP22号端口,以及HTTP80号端口。这些具备特定用途的端口,是由“互联网端口分配认证(IANA)”控制和分配的。从本质上说,端口号可分为“已知”端口、已注册端口、动态和私用端口三类。这三类的端口号分布以下:

l 01023IANA控制,为固定服务保留;

l 102449151IANA列出的已注册端口,供应用程序使用。

l 4915265535是动态和私用端口。

对于TCP/IP协议来讲,若是程序指定的端口是0,则服务提供者会为程序分配一个值在10245000区间的惟一端口。

函数执行成功,会返回0;不然,表示出错。此时,函数WSAGetLastError能返回的错误码以及相应的描述如表11.6所示:

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEACCES

访问权限错误

WSAEADDRINUSE

地址已经与其余套接字绑定,并且没有被设置为可重用

WSAEADDRNOTAVAIL

地址对当前机器来讲不合法或是不可达

WSAEFAULT

参数namenamelen不合法,地址无效

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEINVAL

套接字已经与其余地址绑定

WSAENOBUFS

链接数太多,缓存不足

WSAENOTSOCK

参数s不是一个套接字的句柄

11.6WSAGetLastError能返回的错误码与描述

下面的程序展现如何新建一个套接字,且与当前机器绑定。

// Declare variables

SOCKET ListenSocket;

struct sockaddr_in saServer;

hostent* localHost;

char* localIP;

// Create a listening socket

ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// Get the local host information

localHost = gethostbyname("");

localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);

// Set up the sockaddr structure

saServer.sin_family = AF_INET;

saServer.sin_addr.s_addr = inet_addr(localIP);

saServer.sin_port = htons(5150);

// Bind the listening socket using the

// information in the sockaddr structure

bind( ListenSocket,(SOCKADDR*) &saServer, sizeof(saServer) );

11.1.5 监听套接字

服务器端先建立套接字并与网络地址(通常为全部,即ADDR_ANY指定的网络地址)绑定;而后,进入到监听状态,等待客户端发出链接请求。函数listen的原型以下:

int listen(

  SOCKET s,

  int backlog

);

参数s指定了要监听的套接字句柄。

参数backlog指定了等待链接的最大队列长度。若是backlog被设置为SOMAXCONN,那么服务提供者会为之分配合理范围内的最大值。这个参数的值决定了服务器能同时链接的客户端的数目。若是请求的客户端数目超过了backlog,超出的客户端请求会返回失败。

函数执行成功,则返回0;不然,返回错误SOCKET_ERROR。此时,函数WSAGetLastError能返回的错误码以及相应的描述如表11.7所示:

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEADDRINUSE

地址已经与其余套接字绑定,并且没有被设置为可重用

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEINVAL

套接字没有调用bind函数进行绑定

WSAEISCONN

套接字已经被链接

WSAEMFILE

套接字句柄已达上限

WSAENOBUFS

链接数太多,缓存不足

WSAENOTSOCK

参数s不是一个套接字的句柄

WSAEOPNOTSUPP

套接字句柄不支持listen操做

11-7错误码以及描述说明

11.1.6 等待链接

服务器端在调用listen函数进入到监听状态以后,等待客户端发出链接的请求。服务器端在接收到链接请求后,开始接受客户端的链接。函数accept的功能在于服务器端创建与客户端的链接。函数的原型以下:

SOCKET accept(

  SOCKET s,

  struct SOCK_ADDR* addr,

  int FAR* addrlen

);

参数s指定了进入到监听状态的套接字句柄。

参数addr返回了创建链接的客户端的网络地址。

参数addrlen表示参数addr的长度。

若是套接字是阻塞模式,当等待链接队列中没有链接请求时,函数accept将进入到阻塞状态,直到队列存在等待链接;若是套接字是非阻塞模式,当等待链接队列中存在链接请求,函数accept将接受第一个链接请求,不然返回INVALID_SOCKET

函数执行成功,则返回一个新的套接字句柄,用于与客户端进行数据的发送和接收;不然,返回错误SOCKET_ERROR。此时,函数WSAGetLastError能返回的错误码以及相应的描述以下:如表11-8所示。

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEFAULT

参数addrlen的值过小,或是参数addr不是合法的地址

WSAEINTR

套接字已经被关闭

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEINVAL

在调用accept函数以前,listen函数没有被调用

WSAEMFILE

等待队列为空,没有可用的套接字句柄

WSAENOBUFS

链接数太多,缓存不足

WSAENOTSOCK

参数s不是一个套接字的句柄

WSAEOPNOTSUPP

套接字句柄不支持面向链接的服务

WSAEWOULDBLOCK

套接字的类型是非阻塞型,而当前没有等待的链接请求

11-8错误代码以及描述说明

11.1.7 创建链接

客户端的套接字与服务器端的网络地址绑定成功之后,就能够发起与服务器端的链接。函数connect的功能在于与服务器端创建一个链接。它的原型以下:

int connect(

  SOCKET s,

  const struct SOCK_ADDR* name,

  int namelen

);

参数s指定要链接的客户端的套接字。

参数name指定了要创建链接的服务器端的地址和端口号。

参数namelen指定了参数name的长度。

在阻塞模式下,函数的返回值若是是0,表示执行成功;不然,表示出错,能够调用WSAGetLastError函数查看具体的错误码。在非阻塞模式下,链接请求不能被当即处理。在这种情形下,函数返回SOCKET_ERROR,并且WSAGetLastError函数返回的错误码是WSAEWOULDBLOCK。此时,存在如下三种选择:

1) 利用select函数来判断链接请求是否被处理,这主要是经过检查套接字是否可写来实现的。

2) 若是应用程序使用WSAEventSelect函数来指明链接的事件,须要将当前链接请求的状态(是否成功)传递给相应的事件。

函数WSAGetLastError能返回的错误码以及相应的描述以下:如表11-9所示

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEADDRINUSE

套接字的本地地址已经被占用,并且该地址不能被重用

WSAEINTR

套接字已经被关闭

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEALREADY

指定的套接字中存在正在执行的非阻塞的connect函数调用

WSAEADDRNOTAVAIL

要链接的地址不合法(例如ADDR_ANY

WSAEAFNOSUPPORT

指定的地址与套接字不匹配

WSAECONNREFUSED

链接请求被强制拒绝

WSAEFAULT

参数namenamelen不合法,或是namelen参数的值过小,或者name参数中的地址格式与指定的地址家族的格式不一致

WSAEINVAL

指定的套接字监听状态

WSAEISCONN

套接字已经被链接

WSAENETUNREACH

服务器端的网络不可达

WSAENOBUFS

链接数太多,缓存不足

WSAENOTSOCK

参数s不是一个套接字的句柄

WSAETIMEDOUT

链接超时

WSAEWOULDBLOCK

套接字的类型是非阻塞型,而当前没有等待的链接请求

WSAEACCES

由于套接字的SO_BROADCAST被禁止,将数据包的套接字与广播地址创建链接出错 

11-9错误码以及对应描述

11.1.8 发送数据

在客户端经过connect函数,和服务器端经过accept函数创建相互之间的链接后,二者就能任意地发送或接收数据。

函数send的功能在于向连通的套接字中发送数据。它的原型以下:

int send(

  SOCKET s,

  const char FAR* buf,

  int len,

  int flags

);

参数s指定了要发送数据的套接字,这个套接字必须是连通的。

参数buf是存储了待发送数据的缓冲区。

参数len指定了参数buf的长度,也就是待发送数据的大小。

参数flags指定了函数调用的方式。它的值会影响函数的执行行为。在Windows CE中,它的值只有惟一的MSG_DONTROUTE标志。标志MSG_DONTROUTE代表数据不须要路由,不过Winsock的服务提供者能够选择忽略这个参数。

发送数据的长度是有限制的,它不能超过底层的服务提供者所规定的最大报的长度。函数getsockopt能够获取套接字的SO_MAX_MSG_SIZE属性,也就是当前服务提供者支持的最大数据包的长度。若是长度超过了最大值,函数会返回WSAEMSGSIZE,并且没有数据会被发送。另外,因为在数据传输的过程当中可能发生数据包的丢失,函数send执行成功并不表示数据已经被成功送达。

在阻塞模式下,若是没有足够的空间来缓存全部须要传输的数据,send函数将进入到阻塞状态;而在非阻塞模式下,根据缓存空间的大小不一样,传输的数据能够是1到需传输数据的长度。

若是函数执行成功,将返回实际传输数据的长度。在非阻塞模式下,这个值可能会小于须要传输数据的总长度。若是函数执行错误,会返回SOCKET_ERROR。函数WSAGetLastError能返回的错误码以及相应的描述以下:如表11-10所示

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEACCES

由于套接字的SO_BROADCAST被禁止,将数据包的套接字与广播地址创建链接出错

WSAEINTR

套接字已经被关闭

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAEFAULT

参数buf里面包含了不合法的用户地址空间的地址

WSAENETRESET

由于检测到错误发生,链接被中断

WSAENOBUFS

链接数太多,缓存不足

WSAENOTCONN

套接字没有连通

WSAENOTSOCK

指定的套接字描述符不是合法的套接字

WSAEOPNOTSUPP

属性MSG_OOB被指定,可是该套接字不支持带外数据OOBout of band)的传输

WSAESHUTDOWN

套接字已经被关闭

WSAEWOULDBLOCK

套接字的类型是非阻塞型,而当前没有等待的链接请求

WSAEMSGSIZE

传输的数据超过了底层协议支持的最大长度

WSAEHOSTUNREACH

远程主机不可达

WSAEINVAL

指定的套接字没有处于监听状态,参数flag不被识别,或是属性MSG_OOB在设置了SO_OOBINLINE的套接字中被指定

WSAECONNABORTED

链接超时或发生错误致使虚拟通讯链路被重置

WSAECONNRESET

虚拟通讯链路被远程主机重置

WSAETIMEDOUT

链接超时

11-10错误码以及对应描述

在面向无链接的套接字中(例如数据报服务),尽管套接字中会绑定到特定的网络地址,可是在数据传输时仍须要指定进行通讯的网络地址。函数sendto就是无链接的套接字发送数据的接口。函数sendto的原型以下:

int sendto(

  SOCKET s,

  const char FAR* buf, 

  int len,

  int flags,

  const struct SOCK_ADDR* to,

  int tolen

);

和函数send相比,函数sendto增长了两个参数:totolen。参数to是进行通讯的目标地址,参数tolen表示参数to的大小。

在面向无链接的套接字中,若是套接字已经指定了特定的网络地址,函数sendto的参数to会覆盖这个网络地址;在面向链接的套接字中使用函数sendto发送数据,参数totolen都会被忽略。此时,函数sendto等同于函数send

11.1.9 接收数据

Winsock接收数据的方式也能够分为面向链接和面向无链接的两种方式。函数recv的功能在于从链接的套接字中接收数据。函数recv的原型以下:

int recv(

  SOCKET s,

  char FAR* buf,

  int len,

  int flags

);

参数s指定了要发送数据的套接字,这个套接字必须是连通的。

参数buf是存储了待发送数据的缓冲区。

参数len指定了参数buf的长度,也就是待发送数据的大小。

参数flags指定了函数调用的方式。在Windows CE默认支持的Winsock服务提供者中,有两种常见的网络标志不被支持。这两种标志以下:如表11-11

错误码

描述

MSG_PEEK

能够偷窥接收缓冲区中的内容,即数据能够复制到接收缓冲区,并且也不从输入队列中删除。

MSG_OOB

处理带外数据(Out Of Band

   表11-11错误码以及描述

函数执行成功的时候,返回接收到数据的字节数;若是链接被关闭,则返回0;若是发生错误,函数返回SOCKET_ERROR。函数WSAGetLastError能返回的错误码以及相应的描述如表11-12

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEFAULT

参数buf里面包含了不合法的用户地址空间的地址

WSAENOTCONN

套接字没有连通

WSAEINTR

套接字已经被关闭

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAENETRESET

由于检测到错误发生,链接被中断

WSAENOTSOCK

指定的套接字描述符不是合法的套接字

WSAESHUTDOWN

套接字已经被关闭

WSAEWOULDBLOCK

套接字的类型是非阻塞型,而当前没有等待的链接请求

WSAEMSGSIZE

传输的数据超过了底层协议支持的最大长度

WSAEINVAL

指定的套接字没有处于监听状态,参数flag不被识别,或是属性MSG_OOB在设置了SO_OOBINLINE的套接字中被指定

WSAECONNABORTED

链接超时或发生错误致使虚拟通讯链路被重置

WSAECONNRESET

虚拟通讯链路被远程主机重置

WSAETIMEDOUT

链接超时

11-12错误码以及描述

若是程序使用的是面向链接的协议,在调用函数recv以前套接字必须被连通;若是是面向无链接的协议,套接字必须被绑定。

与函数sendto相对应的是函数recvfrom。函数recvfrom从面向无链接的套接字中接收数据报。它的原型以下:

int recvfrom(

  SOCKET s,

  char FAR* buf,

  int len,

  int flags,

  struct SOCK_ADDR* from,

  int FAR* fromlen

);

函数recvfrom的参数与函数recv的参数相似,只是增长了参数fromfromlen。参数from将返回数据发送方的网络地址,而参数fromlen指定了参数from的长度。与函数recv不一样的是,参数flags的值能够是MSG_PEEKMSG_OOB。函数recvfrom的返回值与函数recv的返回值的意义相同。

11.1.10 设置套接字模式

套接字的工做模式存在阻塞和非阻塞两种方式。在默认状况下,建立的套接字处于阻塞的工做方式。阻塞式工做模式,是指在执行相关的函数时,如connect函数,只有在成功和服务器创建链接或是链接失败时,函数connect才会返回。而非阻塞式工做模式,是指在函数在执行相关函数时,如socket函数,函数当即返回而不阻塞主线程。至于如何判断函数是否执行成功,能够经过select I/O模型来判断。

函数ioctlsocket的功能在于控制套接字的I/O模式。函数ioctlsocket的原型以下:

int ioctlsocket(

  SOCKET s,

  long cmd,

  u_long FAR* argp

);

参数s指定要设置的套接字。

参数cmd指定要设置的命令标识。

参数argp对应于参数cmd,指定要执行的命令值。它是指向一个长整数数值的指针。

函数执行成功会返回0;不然,返回SOCKET_ERROR函数WSAGetLastError能返回的错误码以及相应的描述以下:如表11-13

错误码

描述

WSANOTINITIALISED

必须在成功调用WSAStartup函数以后,才能调用此函数

WSAENETDOWN

网络子系统出错或者相关的服务提供者出现故障

WSAEINPROGRESS

阻塞性的Winsock函数正在被调用,或是服务提供者正在处理回调函数

WSAENOTSOCK

指定的套接字描述符不是合法的套接字

WSAEFAULT

参数argp不是合法的用户地址空间的地址

WSAEINVAL

参数不被支持或是不合法

11-13错误码以及描述

这个函数可以用于任何状态下的任何套接字。它的主要目的是设置或获取套接字相关的操做参数,并且与协议和通讯子系统无关。参数cmd可以支持的命令以下:

1) FIONBIO用于设置套接字是阻塞式仍是非阻塞式。若是参数argp的值是0,则套接字进入到非阻塞模式;若是参数argp的值非0,套接字进入到阻塞模式。在默认状况下,新建立的套接字是阻塞模式。

2) FIONREAD用于获取能够从套接字上读取的数据量,也就是网络的输入缓冲中能够等待的数据量的大小。参数argp为输出类型,保存了套接字能够读取的数据量的大小。若是当前套接字是流式套接字,如SOCK_STREAMFIONREAD返回一次调用过程当中函数recv能读取的最大数据量;这个数据量未必与套接队列中的数据长度一致。若是当前套接字是数据包式套接字,FIONREAD返回套接队列中第一个数据包的长度。

相关文章
相关标签/搜索