




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第8章WinsockAPI8.1字节排序函数8.2IP地址转换函数8.3网络信息获取函数(数据库函数)8.4套接口选项函数8.5套接口I/O处理函数8.6事件对象I/O管理8.7错误处理函数8.8Winsock2支持的其他函数习题8.1字节排序函数 8.1.14字节主机字节顺序的数转化为网络字节顺序——htonl( )和WSAHtonl( ) 1.函数格式 在Winsock1中提供的htonl( )函数的格式是:u_longhtonl( u_longhostlong);
在Winsock2中提供的WSAHtonl( )函数的扩展格式是:intWSAHtonl( SOCKETs, u_longhostlong, u_longFAR*lpnetlong ); 2.函数参数说明 这两个函数中各参数的说明如下: ● hostlong:传入参数,它是一个用主机字节顺序表示的将要被转换为网络字节顺序的32位数(即4个字节的数),u_long表示无符号长整型数。 ● s:传入参数,在Winsock2提供的扩展格式中增加了标识套接口的描述字。 ● lpnetlong:传出参数,一个指向32位的网络字节顺序数的指针。 3.函数返回信息 这两个函数的返回值差别较大,在使用时一定要注意。 对于htonl( )函数来说,如果该函数被调用时正确执行,则这个函数返回一个32位的TCP/IP网络字节顺序的数。 对于WSAHtonl( )函数来说,如果该函数被调用时正确执行,则这个函数的返回值为0,函数返回的32位网络字节顺序的数据是指针参数lpnetlong所指向的数。如果在调用时该函数发生错误,则返回SOCKET_ERROR错误信息,可以进一步使用WSAGetLastError( )函数取得对该错误的具体描述。错误代码如下: ● WSANOTINITIALISED:在调用本API之前应成功调用WSAStartup( )。 ● WSAENETDOWN:网络子系统失效。 ● WSAENOTSOCK:描述字不是一个套接口。 ● WSAEFAULT:指针参数lpnetlong不在有效的用户地址空间中。
4.函数使用说明 该函数的使用比较简单,主要用来将一个32位的IP地址从主机字节顺序转化为网络字节顺序,具体用法可以参考第7章的网络程序实例。 8.1.22字节主机字节顺序的数转化为网络字节顺序——htons( )和WSAHtons( ) 1.函数格式在Winsock1中提供的htons( )函数的格式是:
u_shorthtons(u_shorthostshort);
在Winsock2中提供的WSAHtons( )函数的扩展格式是:
u_shortWSAHtons(SOCKETs,u_shorthostshort,u_shortFAR*lpnetshort); 2.函数参数说明 这两个函数中各参数的说明如下: ● hostshort:传入参数,它是一个以主机字节顺序表示的将要被转换为网络字节顺序的16位数(即2字节数),u_short表示无符号短整型数。 ● s:传入参数,Winsock2提供的扩展格式中增加的标识套接口的描述字。 ● lpnetshort:传出参数,一个指向16位网络字节顺序数的指针。 3.函数返回信息
htons( )函数如果被调用时正确执行,则这个函数返回一个16位TCP/IP网络字节顺序的数。
WSAHtons( )函数如果被调用时正确执行,则这个函数返回0,函数返回的16位网络字节顺序的数据是指针参数lpnetshort所指向的数。如果在调用时该函数发生错误,则返回SOCKET_ERROR错误信息,可以进一步使用WSAGetLastError( )函数取得对该错误的具体描述。错误代码与WSAHtonl( )函数的错误代码类似。
4.函数使用说明 该函数一般用来将一个16位的TCP或UDP端口号从主机字节顺序转化为网络字节顺序,用法可以参考第7章的程序实例。 8.1.34字节网络字节顺序的数转化为主机字节顺序——ntohl( )和WSANtohl( ) 1.函数格式 在Winsock1中提供的ntohl( )函数的格式是:
u_longntohl( u_longnetlong );
在Winsock2中提供的WSANtohl( )函数的扩展格式是:
u_longWSANtohl( SOCKETs, u_longnetlong, u_longFAR*lphostlong ); 2.函数参数说明 这两个函数的参数说明如下: ● netlong:传入参数,一个以网络字节顺序表示的32位数。 ● s:传入参数,在Winsock2中提供的扩充格式中增加的标识套接口的描述字。 ● lphostlong:传出参数,指向一个32位主机字节顺序数的指针。
3.函数返回信息
ntohl( )函数在调用成功后,返回一个主机字节顺序的32位数。 WSANtohl( )函数在调用正确时返回0,函数返回的32位主机字节顺序的数据是指针参数lphostlong所指向的数。如果调用错误,则返回错误信息SOCKET_ERROR,可以进一步使用WSAGetLastError( )函数取得对该错误的具体描述。具体错误代码与WSAHtonl( )函数的错误代码类似。
4.函数使用说明 该函数常用来将一个网络字节顺序表示的32位IP地址转化为主机字节顺序。 8.1.42字节网络字节顺序的数转化为主机字节顺序——ntohs( )和WSANtohs( ) 1.函数格式 在Winsock1中提供的ntohs( )函数的格式是:
u_shortntohs( u_shortnetshort );
在Winsock2中提供的WSANtohs( )函数的扩展格式是:
u_shortWSANtohs( SOCKETs, u_shortnetshort, u_shortFAR*lphostshort ); 2.函数参数说明 这两个函数的参数说明如下: ● netshort:传入参数,一个以网络字节顺序表示的16位数。 ● s:传入参数,在Winsock2提供的扩充格式中增加的一个标识套接口的描述字。 ● lphostshort:传出参数,指向一个16位主机字节顺序数的指针。 3.函数返回信息
ntohs( )函数在调用成功后,返回一个主机字节顺序的16位数。
WSANtohs( )函数在调用正确时返回0,函数返回的16位主机字节顺序的数据是指针参数lphostshort所指向的数。如果调用错误,则返回错误信息SOCKET_ERROR,可以进一步使用WSAGetLastError( )函数取得对该错误的具体描述。具体错误代码与WSAHtonl( )函数的错误代码类似。
4.函数使用说明 该函数常用来将一个网络字节顺序表示的16位TCP或UDP端口号转化为主机字节顺序。8.2IP地址转换函数 8.2.1点分十进制数表示的IP地址转换为网络字节顺序的IP地址——inet_addr( ) 1.函数格式
inet_addr( )函数的格式如下:
unsignedlonginet_addr(constcharFAR*cp ); 2.函数参数说明 该函数中的参数cp为传入参数,是一个以“.”间隔的字符串,即一个点分十进制数表示的IP地址。
3.函数返回信息 该函数调用成功后,返回一个无符号长整型数(UnsignedLong),它是以网络字节顺序表示的32位二进制IP地址。如果传入的字符串不是一个合法的Internet地址,如当“a.b.c.d”地址中任一项超过255时,则inet_addr( )返回INADDR_NONE提示信息。 4.函数使用说明 当IP地址用点分十进制数表示时,即4个字节的数以“.”间隔,则用这种格式书写的IP地址可有下列4种表示方式。
(1) a.b.c.d:当四个部分都有固定的值时,则每一个部分被解释成一个字节的数据,从左到右组成Internet4字节地址。请注意,当一个Internet地址在Intel机器上表示成一个32位整型数时,则上述数据在计算机内部的表示为“d.c.b.a”。这是因为在Intel处理器内部,字中的字节是按由低到高的顺序存储的,即“小序在前”。 (2)a.b.c:对于一个只有三个部分组成的IP地址,最后一部分被解释成16位数据,并作为网络地址最右边的两个字节。
(3)a.b:对于一个只有两个部分组成的IP地址,最后一部分解释成24位数据,并作为网络地址最右边的三个字节。
(4)a:对于一个仅有一个部分的IP地址,将它的值直接存入网络地址而不做任何字节重组。 该函数的用法见第7章中的客户程序实例。 8.2.2网络字节顺序的IP地址转换为点分十进制数表示的IP地址——inet_ntoa( ) 1.函数格式
inet_ntoa( )函数的格式如下:
char*inet_ntoa( structin_addrin ); 2.函数参数说明 该函数中的参数in为传入参数,表示一个结构型的IP主机地址。 3.函数返回信息 该函数调用成功后,返回一个指向字符的指针,该指针指向一个文本型的缓冲区,缓冲区中存有用点分十进制形式表示的IP地址。如果函数调用失败的话,则返回一个空指针(NULL)。
4.函数使用说明 该函数的用法参见第7章中的服务器程序实例。8.3网络信息获取函数(数据库函数) 8.3.1获得主机名——gethostname( ) gethostname( )函数用来取得一台主机的名称信息。
1.函数格式 该函数的格式如下:
intgethostname( charFAR*name, intnamelen ); 2.函数参数说明
gethostname( )函数中各参数的说明如下: ● name:传出参数,一个指向将要存放主机名的缓冲区指针,当函数调用完成时,主机名被存入该缓冲区中。 ● namelen:传入参数,缓冲区的长度。
3.函数返回信息 如果函数调用时没有发生错误,则gethostname( )函数返回0。如果函数调用失败,则返回SOCKET_ERROR错误信息。应用程序可以通过WSAGetLastError( )来得到一个特定的错误代码,错误代码说明如下:
● WSAEFAULT:名字长度参数太小。 ● WSANOTINTIALISED:在应用这个API前,必须成功调用WSAStartup( )。 ● WSAENETDOWN:WindowsSockets实现检测到了网络子系统的错误。 ● WSAEINPROGRESS:一个阻塞的WindowsSockets操作正在进行。
4.函数使用说明 该函数把本地主机名存放入由name参数指定的缓冲区中。主机名的形式取决于WindowsSockets系统的实现,它可能是一个简单的主机名,或者是一个域名。不管是哪种形式,该函数返回的名字必定可以在gethostbyname( )和WSAAsyncGetHostByName( )函数中使用。 8.3.2获得与套接口相连的远程协议地址——getpeername( ) 1.函数格式
getpeername( )函数的格式如下:
intgetpeername( SOCKETs, structsockaddrFAR*name, intFAR*namelen ); 2.函数参数说明 该函数中各参数的说明如下: ● s:传入参数,一个已建立连接的套接口描述字。 ● name:传出参数,指向返回的远程协议地址。 ● namelen:传出参数,远程协议地址长度。
3.函数返回信息 调用该函数时若无错误发生,则getpeername( )函数返回0。如果调用失败,则返回SOCKET_ERROR错误信息,应用程序可通过调用WSAGetLastError( )函数来获取对该错误的进一步描述。可获得的错误代码如下: ● WSANOTINITIALISED:在使用此API之前应成功调用WSAStartup( )。 ● WSAENETDOWN:Windows套接口实现检测到网络子系统失效。 ● WSAEFAULT:namelen参数不够大。 ● WSAEINPROGRESS:一个阻塞的Windows套接口调用正在运行中。 ● WSAENOTCONN:套接口未建立连接。 ● WSAENOTSOCK:描述字不是一个套接口。 4.函数使用说明
getpeername( )函数用于从套接口s中获取与它绑定的远程协议的地址信息,并把它存放在sockaddr类型的name结构中。它只能用于已经建立连接的套接口。对于数据报类型的套接口来说,它只能返回先前调用connect( )函数时使用的对等端信息,在sendto( )函数中使用过的对等端信息不能被返回。 8.3.3获得套接口本地协议地址——getsockname( ) 1.函数格式
getsockname( )函数的格式如下:
intgetsockname( SOCKETs, structsockaddrFAR*name, intFAR*namelen ); 2.函数参数说明 该函数的参数说明如下: ● s:传入参数,标识一个套接口的描述字。 ● name:传出参数,指向返回的本地协议地址的指针。 ● namelen:传出参数,本地协议地址长度。当函数调用完成时, 它可以返回实际的本地地址长度。 3.函数返回信息 调用该函数时若无错误发生,则getsockname( )函数返回0。如果调用失败,则返回SOCKET_ERROR错误信息,应用程序可通过WSAGetLastError( )函数来获取如下的错误代码: ● WSANOTINITIALISED:在使用此API之前应成功调用WSAStartup( )。 ● WSAENETDOWN:Windows套接口实现检测到网络子系统失效。 ● WSAEFAULT:namelen参数不够大。 ● WSAEINPROGRESS:一个阻塞的Windows套接口调用正在运行中。 ● WSAENOTSOCK:描述字不是一个套接口。 ●WSAEINVAL:套接口未用bind( )捆绑。 4.函数使用说明
getsockname( )函数用于获取一个套接口的协议地址,它用于一个已绑定或已连接套接口。本调用特别适用于如下情况:未调用bind( )就调用了connect( ),这时惟有getsockname( )调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。 若一个套接口与INADDR_ANY绑定,即该套接口可以用任意的主机地址,此时除非调用connect( )或accept( )来连接,否则getsockname( )将不会返回主机IP地址的任何信息。除非套接口被连接,Windows套接口应用程序不应假设IP地址会从INADDR_ANY变成其他地址。这是因为对于一个有多个IP地址的主机来说,除非套接口被连接,否则该套接口所用的IP地址是不可知的(即不能被确定是哪一个)。 8.3.4根据主机名取得主机信息——gethostbyname( )或WSAAsyncGetHostByName( ) gethostbyname( )和WSAAsynGetHostByName( )这两个WinsockAPI函数从主机数据库中取回与指定的主机名对应的主机信息。这两个函数均返回一个hostent结构型的量,所以先介绍一下该结构的格式。hostent结构的定义如下:
structhostent{ char FAR*h_name; /*officialnameofhost*/ char FAR*FAR*h_aliases; /*aliaslist*/ short h_addrtype; /*hostaddresstype*/
shorth_length;/*lengthofaddress*/ char FAR*FAR*h_addr_list; /*listofaddresses*/ #define h_addrh_addr_list[0] /*address,forbackwardcompat*/ };
该结构中各字段的含义如下: ● h_name:该字段是正式的主机名。 ● h_aliases:它是二维字符指针,返回一台主机的所有别名(即别名列表)。 ● h_addrtype:表示主机地址类型,如AF_INET表示IPv4地址。 ● h_length:该字段可以返回主机地址的字节数。 ● h_addr_list:该字段返回一个主机的所有IP地址,因为一台主机可以分配若干个IP地址(当然这主要是对服务器而言的)。这个数组中的每个地址都是按网络字节顺序返回的。一般情况下,应用程序都采用该数组中的第一个地址。但是,如果返回的地址不止一个,应用程序就会相应地选择一个最恰当的地址,而不是一直都用第一个地址。 ● h_addr:是为了保持向后兼容而定义的字段,一般很少使用。
1.函数格式 在Winsock1中提供的gethostbyname( )函数的格式是:
structhostentFAR*gethostbyname( constcharFAR*name );
在Winsock1中提供的异步扩WSAAsyncGetHostByName( )函数的格式是:
HANDLEWSAAsyncGetHostByName( HWNDhWnd, unsignedintwMsg, constcharFAR*name, charFAR*buf, intbuflen ); 2.函数参数说明
gethostbyname( )函数中各参数的说明如下: ● name:传入参数,是一个指向主机名的指针。
WSAAsyncGetHostByName( )函数是一个Windows异步扩展函数,它在函数结束时,利用Windows消息向应用程序发出通知,其各参数的含义是: ● hWnd:传入参数, 是一个窗口句柄, 表示当异步请求完成时,该窗口句柄应该收到一条消息。 ● wMsg:传入参数,当异步请求完成时,将要接收的消息。 ● name:传入参数,指向主机名的指针。 ● buf:传出参数, 接收hostent数据的数据区指针。注意该数据区必须大于hostent结构的大小,这是因为WindowsSockets实现不仅要用该数据区容纳hostent结构,而且hostent结构的成员引用的所有数据也要在该区域内。建议用户提供一个MAXGETHOSTSTRUCT字节大小的缓冲区。 ● buflen:传入参数,上述数据区的大小。 3.函数返回信息 调用该函数时如果没有错误发生,gethostbyname( )函数返回如上所述的一个指向hostent结构的指针。如果调用失败则返回一个空指针,应用程序可以通过WSAGetLastError( )来得到一个特定的错误代码,错误代码说明如下: ● WSANOTINTIALISED:在应用这个API前,必须成功调用WSAStartup( )。 ● WSAENETDOWN:WindowsSockets实现检测到了网络子系统的错误。 ● WSAHOST_NOT_FOUND:没有找到授权应答主机。 ● WSATRY_AGAIN:没有找到非授权主机,或者服务器故障(SERVERFAIL)。 ● WSANO_RECOVERY:无法恢复的错误,如查询有格式错误(FORMERR)、拒绝服务(REFUSED)没有通信处理机、(NOTIMP)。 ● WSANO_DATA:有效的名字,但没有关于请求类型的数据记录。 ● WSAEINPROGRESS:一个阻塞的WindowsSockets操作正在进行。 ● WSAEINTR:阻塞调用被WSACancelBlockingCall( )取消了。
4.异步扩展函数返回信息
WSAAsyncGetHostByName( )函数是gethostbyname( )函数的Windows异步扩展函数。所谓“异步”,指的是WindowsSockets的实现启动该操作后立刻回到调用方,并传回一个异步任务句柄,应用程序可以用它来标识该操作。 当异步操作完成时,如果成功则将主机名和地址信息拷贝到buf缓冲区中,同时向句柄为hWnd的应用程序窗口发送一条消息(wMsg)。wParam参数包含了初次函数调用时返回的异步任务句柄,lParam的高16位包含着错误代码,该代码可以是Winsock2.h中定义的任何错误。错误代码为0说明异步操作成功,在成功完成的情况下,提供给初始函数调用的缓冲区中包含了一个hostent结构。为存取该结构中的元素,初始的缓冲区指针应置为hostent结构的指针。
若错误代码为WSAENOBUFS,则说明在初始调用时由buflen指出的缓冲区大小对于容纳所有的结果信息来说太小了。在这种情况下,lParam的低16位提供所有信息所需的缓冲区大小。如果应用程序认为获取的数据不够,它就可以在设置了足够容纳所需信息的缓冲区(也就是大于lParam低16位提供的数值)后,重新调用WSAAsyncGetHostByName( )函数。 错误代码和缓冲区大小应使用WSAGETASYNCERROR和WSAGETASYNCBUFLEN宏从lParam中取出。这两个宏的定义如下:
#defineWSAGETASYNCERROR(lParam) HIWORD(lParam) #defineWSAGETASYNCBUFLEN(lParam) LOWORD(lParam)
使用这些宏可以最大限度地提高应用程序源代码的可移植性。 函数的返回值指出异步操作是否成功启动,注意它并不隐含操作本身的成功或失败(后面要介绍的其他异步函数的返回值也与它类似)。
若操作成功启动,则WSAAsyncGet-HostByName( )返回一个HANDLE类型的非0值,它用来标识该异步请求任务的句柄。通过该句柄使用WSACancelAsyncRequest( )函数可取消该操作,也可通过检查wParam消息参数,以匹配异步操作和完成消息。如果异步操作不能启动,WSAAsyncGetHostByName( )返回一个0值,并且可使用WSAGetLastError( )函数来获取如下的错误代码: ●WSANOTINITIALISED:在使用本API前必须进行一次成功的WSAStartup( )调用。 ● WSAENETDOWN:WindowsSockets实现已检测到网络子系统故障。 ● WSAEINPROGRESS:一个阻塞的WindowsSockets操作正在进行。 ● WSAEWOULDBLOCK:本异步操作此时由于WindowsSockets实现的资源或其他限制的制约而无法调度。在应用程序的窗口收到消息时可能会设置下列错误代码,它们可以通过WSAGETA-SYNCERROR宏从应答的消息lParam中取出: ● WSAENETDOWN:WindowsSockets实现已检测到网络子系统故障。 ● WSAENOBUFS:可用的缓冲区空间不足或没有。 ● WSAHOST_NOT_FOUND:未找到授权应答主机。 ● WSATRY_AGAIN:未找到非授权应答主机,或SERVERFAIL。 ● WSANO_RECOVERY:不可恢复性错误。 ● WSANO_DATA:无请求类型的数据记录。 8.3.5根据主机地址取得主机信息——gethostbyaddr( )或WSAAsyncGetHostByAddr( )
这两个函数可以根据主机的IP地址取得主机名和主机地址等信息。
1.函数格式 在Winsock1中提供的gethostbyaddr( )函数的格式是:
structhostentFAR*gethostbyaddr( constcharFAR*addr, intlen, inttype );
在Winsock1中提供的异步扩展WSAAsyncGetHostByAddr( )函数的格式是:
HANDLEWSAAsyncGetHostByAddr( HWNDhWnd, unsignedintwMsg, constcharFAR*addr, intlen, inttype, charFAR*buf, intbuflen ); 2.函数参数说明
gethostbyaddr( )函数的参数说明如下: ● addr:传入参数,指向网络字节顺序地址的指针。 ● len:传入参数,地址的长度,如果是IPv4类型的地址,则该值为4。 ● type:传入参数,地址类型,如为AF_INET。
WSAAsyncGetHostByAddr( )函数是gethostbyaddr( )函数的异步版本。它的其他参数以及返回信息与WSAAsyncGetHostByName( )函数完全相同。
3.函数返回信息 这两个函数返回的信息与通过名称获取主机信息的gethostbyname( )函数相同。
8.3.6根据协议名取得主机协议信息——getprotobyname( )或WSAAsync-GetProtoByName( )
函数getprotobyname()WSAAsyncGetProtoByName()可以根据协议名称返回对应的相关协议信息。它们都要使用到一个与协议有关的结构,该结构的定义如下:
structprotoent{ char FAR*p_name; char FAR*FAR*p_aliases; shortp_proto; };
该结构的成员有: ● p_name:正式的协议名。 ● p_aliases:它是二维字符指针,返回一个协议的所有别名。 ● p_proto:以主机字节顺序排列的协议号。 1.函数格式 在Winsock1中提供的getprotobyname( )函数的格式是:
structprotoentFAR*getprotobyname( constcharFAR*name );
在Winsock1中提供的异步扩展WSAAsyncGetProtoByName( )函数的格式是:
HANDLEWSAAsyncGetProtoByName( HWNDhWnd, unsignedintwMsg, constcharFAR*name, charFAR*buf, intbuflen ); 2.函数参数说明
getprotobyname( )函数中的参数name为传入参数,指向协议名的指针。 异步扩展格式中的buf是接收protoent数据的缓冲区指针,buflen为该缓冲区的大小。其他参数与WSAAsyncGetHostByName( )函数中的参数相同,返回信息的含义也一样。
3.函数返回信息 如果没有错误发生,getprotobyname( )返回如上所述的一个指向protoent结构的指针,如果调用失败,则返回一个空指针。应用程序可以通过WSAGetLastError( )来得到一个如下所示的特定错误代码: ● WSANOTINTIALISED:在应用这个API前,必须成功调用WSAStartup( )。 ● WSAENETDOWN:WindowsSockets实现检测到了网络子系统的错误。 ● WSANO_RECOVERY:无法恢复的错误,如FORMERR、REFUSED、NOTIMP等。 ● WSANO_DATA:有效的名字,但没有关于请求类型的数据记录。
● WSAEINPROGRESS:一个阻塞的WindowsSockets操作正在进行。 ● WSAEINTR:阻塞调用被WSACancelBlockingCall( )取消了。 ● WSAHOST_NOT_FOUND:没有找到协议。 ● WSATRY_AGAIN:非正式的协议没有找到或服务器失败。 ● WSAEFAULT:name参数不在有效的用户地址空间。 8.3.7根据协议号取得主机协议信息——getprotobynumber( )或WSAAsyncGetProtoByNumber( ) getprotobynumber( )和WSAAsyncGetProtoByNumber返回对应于给定协议号的相关协议信息。
1.函数格式 在Winsock1中提供的getprotobynumber( )函数的格式是:
structprotoentFAR*getprotobynumber( intnumber );
在Winsock1中提供的异步扩展WSAAsyncGetProtoByNumber( )函数的格式是:
HANDLEWSAAsyncGetProtoByNumber( HWNDhWnd, unsignedintwMsg, intnumber, charFAR*buf, intbuflen ); 2.函数参数说明 参数number表示传入参数,是一个以主机字节顺序排列的协议号。异步扩展格式中的其他参数与WSAAsyncGetHostByName( )函数中的参数含义相同。
3.函数返回信息 函数的返回信息与通过协议名获取主机协议信息时的情况相同。 8.3.8根据服务名取得相关服务信息—— getservbyname( )或WSAAsync-GetServByName( ) getservbyrvame( )和WSAAsyncGetServByName( )函数用于返回对应于给定服务名和协议名的相关服务信息。这两个函数都要用到一个如下所示的结构:
structservent{ charFAR*s_name; charFAR*FAR*s_aliases; shorts_port; charFAR*s_proto; };
该结构中各成员的含义如下: ● s_name:正规的服务名。 ● s_aliases:所有其他的可选服务名。 ● s_port:连接该服务时需要用到的端口号,返回的端口号是以网络字节顺序排列的。 ● s_proto:连接该服务时用到的协议名。 1.函数格式 在Winsock1中提供的getservbyname( )函数的格式是:
structserventFAR*getservbyname( constcharFAR*name, constcharFAR*proto );
在Winsock1中提供的异步扩展WSAAsyncGetServByName( )函数的格式是: HANDLEWSAAsyncGetServByName( HWNDhWnd, unsignedintwMsg, constcharFAR*name, constcharFAR*proto, charFAR*buf, intbuflen ); 2.函数参数说明 这两个函数中各参数的说明如下: ● name:传入参数,一个指向服务名的指针。 ●proto:传入参数,指向协议名的指针(可选)。如果这个指针为空,getservbyname( )返回第一个name与s_name或者某一个s_aliases匹配的服务条目。否则,getservbyname( )对name和proto都进行匹配。 其他参数与WSAAsyncGetHostByName( )函数中的参数含义相同。 8.3.9根据端口号取得相关服务信息——getservbyport( )或WSAAsync-GetServByPort( ) getservbyport( )和WSAAsyncGetServByPort( )函数用于返回对应于给定端口号和协议名的相关服务信息。
1.函数格式 在Winsock1中提供的getservbyport( )函数的格式是:
structserventFAR*getservbyport( intport, constcharFAR*proto );
在Winsock1中提供的异步扩展WSAAsyncGetServByPort( )函数的格式是:
HANDLEWSAAsyncGetServByPort( HWNDhWnd, unsignedintwMsg, intport, constcharFAR*proto, charFAR*buf, intbuflen ); 2.函数参数说明 这两个函数中需要说明的参数如下: ● port:传入参数,给定的端口号,以网络字节顺序排列。 ●proto:传入参数,指向协议名的指针(可选)。如果这个指针为空,getservbyport( )返回第一个port与s_port匹配的服务条目。否则,getservbyport( )对port和proto都进行匹配。 其他参数与WSAAsyncGetHostByName( )函数中的参数含义相同。 8.3.10网络信息获取函数应用实例 本小节举一个实例来说明以上介绍的网络信息获取函数的用法。本实例只使用了三个比较典型的函数,其他函数的用法与此类似。要说明的是,虽然这只是一个关于网络信息获取函数用法的实例,但该程序也是一个非常有用的实用程序,它可以获得一台主机的主机名、主机别名(如果有的话)、主机IP地址列表等信息。
/*************************************************************************
调试环境:VC++6.0
程序名称:host.cpp
程序功能:该程序使用网络信息获取函数取得主机的有关信息,在程序中使用了以下三个函数: gethostname( ) gethostbyname( ) getprotobyname( )
命令格式:host**************************************************************************/ #include<winsock2.h> #include<stdio.h> #include<stdlib.h> voidmain( ) { WSADATA wsaData; int n; //存放主机名称
char hostname[256]; //主机信息指针
hostent *pHostent; //主机协议信息指针
protoent *pProtoent; structsockaddr_in sa; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { printf("FailedtoloadWinsock.\n"); return; } printf("---------------------------------------------\n");//获得主机名
if(gethostname(hostname,sizeof(hostname))!=0){printf("gethostname( )Error:%u\n",WSAGetLastError( ));return;} printf("以下信息由gethostname( )函数取得\n"); printf("Localhostname:%s\n",hostname); printf("---------------------------------------------\n"); //根据主机名获取主机信息
pHostent=gethostbyname(hostname); if(pHostent==NULL) { printf("gethostbyname( )Error:%u\n",WSAGetLastError( )); return; } //解析返回的hostent结构中名称、别名、地址类型和地址长度信息
printf("以下信息由gethostbyname( )函数取得\n"); printf("name:%s\naliases:%s\naddrtype:%d\nlength:%d\n",pHostent->h_name, pHostent->h_aliases, pHostent->h_addrtype, pHostent->h_length); //解析hostent结构中的主机地址
for(n=0;pHostent->h_addr_list[n];n++){memcpy(&sa.sin_addr.s_addr,pHostent->h_addr_list[n],pHostent->h_length);//输出主机IP地址.printf("Address:%s\n",inet_ntoa(sa.sin_addr));}printf("---------------------------------------------\n");//根据协议名获得协议信息
pProtoent=getprotobyname("tcp");if(pProtoent==NULL) {printf("getprotobyname( )Error:%u\n",WSAGetLastError( ));return;}//解析protoent结构中的信息
printf("以下信息由getprotobyname( )函数取得\n");printf("name:%s\nproto:%d\n",pProtoent->p_name, pProtoent->p_proto); for(n=0;pProtoent->p_aliases[n];n++) {printf("aliases:%s\n",pProtoent->p_aliases[n]);}WSACleanup( ); }
程序的运行结果如图8-1所示。图8-1网络信息获取函数使用实例程序的运行结果8.4套接口选项函数 8.4.1套接口选项函数说明
1.函数格式 套接口选项获取函数getsockopt( )的格式如下:
intsetsockopt( SOCKETs, intlevel, intoptname, constcharFAR*optval, intoptlen );
套接口选项设置函数setsockopt( )的格式如下:
intgetsockopt( SOCKETs, intlevel, intoptname, charFAR*optval, intFAR*optlen ); 2.函数参数说明
setsockopt( )函数和getsockopt( )函数的参数是一样的,但 setsockopt( )函数的optval和optlen选项应该由应用程序填写,而getsockopt( )函数的这两个选项是返回值,由系统来填写。 函数中各参数的含义如下: ●s:传入参数,参数s指定一个有效的套接口,我们要对这个套接口的选项进行操作。 ● level:传入参数,套接口选项定义的级别(层次)。常用的级别有SOL_SOCKET、IPPROTO_IP和IPPROTO_TCP,在8.4.2~8.4.4节将对这些级别对应的选项进行专门介绍。 ● optname:传入参数,需设置或获取的套接口选项,这些选项的名称均是在Winsock头文件内定义的常数值。 ● optval:对于setsockopt( )函数来说, 它是传入参数;对于getsockopt( )函数来说,它是传出参数。该参数是指向存放选项值缓冲区的指针。 ● optlen:对于setsockopt( )函数来说, 它是传入参数;对于getsockopt( )函数来说,它既是传出参数也是传入参数。该参数是指向optval缓冲区长度(或套接口选项变量的长度)的指针。 3.函数返回信息 若函数调用时无错误发生,则setsockopt( )函数和getsockopt( )函数都返回0。如果调用发生错误,则返回SOCKET_ERROR错误信息,应用程序可通过WSAGetLastError( )函数获取对错误信息的进一步说明。以下是错误代码的含义说明: ● WSANOTINITIALISED:在使用此API之前应成功调用WSAStartup( )。 ● WSAENETDOWN:Windows套接口实现已检测到网络子系统失效。 ● WSAEFAULT:setsockopt( )函数返回时,表示optval不是进程地址空间中的一个有效部分;getsockopt( )函数返回时,表示optlen参数非法。 ● WSAEINPROGRESS:一个阻塞的Windows套接口调用正在运行中。 ● WSAEINVAL:level值非法,或optval中的信息非法。 ● WSAENETRESET:当SO_KEEPALIVE设置后连接超时。 ● WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM类型的套接口不支持SO_DONTLINGER、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。 ● WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。 ● WSAENOTSOCK:描述字不是一个套接口。 8.4.2SOL_SOCKET选项级别
SOL_SOCKET选项级别主要针对传输层协议(TCP或UDP)。在SOL_SOCKET选项级别下,套接口的选项有两种类型:一种是值为布尔型(BOOL)的选项,这种选项可以允许或禁止一种特性;另一种是值为整型(int)或结构型(StructLinger)的选项,这种选项可以用来设置系统工作时的某些参数。
允许一个布尔型选项,则将optval指向一个非零的整型数;禁止一个布尔型选项,则可以将optval指向一个等于零的整型数。对于布尔型选项,optlen应等于sizeof(int)。对于非布尔型的其他选项,optval应该指向包含所需选项的整型量或结构量,而optlen则为整形量或结构量的长度。 还要注意一个问题,套接口的有些属性值既可以设置(即可以使用setsockopt( )函数),也可以获取(即使用getsockopt( )函数),但有些套接口属性只能获取或只能设置。 后面要介绍的其他两种选项级别(IPPROTO_IP和IPPROTO_TCP)与SOL_SOCKET选项级别的情况类似。 表8-1所示为在SOL_SOCKET选项级别下的各种选项。表8-1SOL_SOCKET选项级别下的各选项 (1) SO_ACCEPTCONN:该选项只能获取。如果已通过listen( )函数调用, 套接口将进入监听模式,这时获取这个选项时就会返回TRUE。数据报类型的套接口(SOCK_DGRAM)不支持这一选项。
(2) SO_BROADCAST: 该选项可以获取也可以设置。如果指定的套接口该选项已经设置为TRUE,则允许套接口广播收发信息。该选项只有对非SOCK_STREAM类型的所有套接口才是有效的。
广播是一种特殊的数据发送方法,使本地子网上的所有机器都能收到相同的数据。广播通信的缺点在于假如同时有许多进程发送广播数据,网络立刻就会拥挤不堪,造成网络性能大大降低,甚至有可能陷入瘫痪。要想接收一条广播消息,首先必须启用广播选项,然后使用某个数据报接收函数,比如recvfrom( )或WSARecvFrom( )。该选项的设置方法如下: …… BOOLbBroadcast=TRUE; //创建一个数据报套接口
s=socket(AF_INET,SOCK_DGRAM,0); …… //设置广播选项
if(setsocketopt(s,SOL_SOCKET,SO_BROADCAST,(char*)&bBroadcast,sizeof(BOOL))==SOCKET_ERROR) { printf(''setsocketopt( )Error:u%\n'',WSAGetLastError( )); return; } …… (3) SO_CONNECT_TIME:该选项只能获取。它是一个微软Windows操作系统专用选项,用于返回连接建立的时间,以秒为单位。该选项可以在客户端的SOCKET句柄上调用,以判断连接是否已经建立,以及建立了多长时间。若套接口当前尚未建立连接,返回值便是0xFFFFFFFF。
(4) SO_DEBUG:该选项值可以获取,也可以设置。在应用程序设置了SO_DEBUG选项的情况下,系统将记录调试信息。至于调试信息如何展示,要取决于服务提供者的基层实施方式。要想打开调试信息,可调用setsockopt( )函数设置SO_DEBUG为TRUE。若用SO_DEBUG选项调用getsockopt( )函数,会返回TRUE或FALSE,分别代表允许和禁止记录调试信息。但目前尚无任何一种Win32平台支持的SO_DEBUG选项。 (5) SO_LINGER:该选项值可以获取,也可以设置。该选项不能使用在SOCK_DGRAM类型的套接口上。它用于控制在closesocket( )函数已执行的情况下,如何处理套接口数据排列上未发送完毕的数据。该选项要通过linger结构来设置,该结构的定义如下:
structlinger{ intl_onoff; intl_linger; };
l_onoff字段用来控制SO_LINGER选项的打开或关闭,为了使该选项起作用,该字段应该设置为一个非0的值。l_linger字段表示延迟时间,以秒为单位。 当l_onoff和l_linger字段取不同的值时,系统的操作方式也不同,它们的取值情况如表8-2所示。表8-2SO_LINGER选项取值情况说明 (6) SO_DONTLINGER:该选项值可以获取,也可以设置。若在一个流类套接口上设置了SO_DONTLINGER选项,也就是说将linger结构的l_onoff域设为0,则closesocket( )调用立即返回,但是,如果可能,排队的数据将在套接口关闭之前被发送。SO_DONTLINGER和SO_LINGER选项将直接影响使用closesocket( )函数关闭一个套接口时系统对套接口的操作行为。表8-3总结了这两个选项对套接口关闭方式的影响。表8-3SO_DONTLINGER和SO_LINGER选项对套接口关闭方式的影响 (7) SO_DONTROUTE:该选项可以获取,也可以设置。
(8) SO_ERROR:该选项只能获取,用于返回以具体套接口为基础的错误代码,在返回后系统一般将该选项设置为0。
(9) SO_KEEPALIVE:该选项可以获取,也可以设置,它只适用于以TCP为基础的套接口。在Windows95及Windows98操作系统中,这两个键都位于下述注册表路径中:\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP
而在WindowsNT和Windows2000中,这两个键位于下述位置:
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters服务器(例如FTP服务器)一般要设置该选项,这样当客户在非正常终止连接的情况下,经过一段时间后,服务器也能终止该连接。
(10) SO_MAX_MSG_SIZE:该选项只能获取。
(11) SO_OOBINLINE:该选项可以获取,也可以设置。 (12) SO_PROTOCOL_INFO:该选项只能获取,获取WSAPROTCOL_INFO结构中与套接口关联在一起的协议特征信息。该选项由Winsock2支持。
(13) SO_RCVBUF:该选项可以获取,也可以设置。
(14) SO_SNDBUF:该选项可以获取,也可以设置。与SO_RCVBUF选项相对应,该选项用于确定发送缓冲区的大小。
(15) SO_TYPE:该选项只能获取, 用于返回指定套接口的类型。可能的套接口类型包括SOCK_DGRAM、SOCK_STREAM和SOCK_RAW。
(16) SO_SNDTIMEO:该选项可以获取,也可以设置。 (17) SO_RCVTIMEO:该选项可以获取,也可以设置。
(18) SO_REUSEADDR:该选项可以获取,也可以设置,表示该套接口能和一个已在使用中的地址捆绑。
(19) SO_EXCLUSIVEADDRUSE:该选项可以获取,也可以设置。该选项的作用是禁止其他进程在一个本地地址上使用SO_REUSEADDR(重复使用地址)。 8.4.3IPPROTO_IP选项级别 该选项级别包括的主要选项如表8-4所示。表8-4IPPROTO_IP级别套接口选项 (1) IP_OPTIONS:该选项可以获取,也可以设置。它是专门针对IP数据报选项字段的,通过该选项字段,用户可以获取IP数据报头选项字的设置情况,也可以对IP选项字段进行设置。IP数据报选项的格式如图2-12所示。 ●记录路由:IP数据报在传输过程中,每经过一个路由器,路由器就将自己的IP地址添加到IP数据报头内的选项字段位置。 ●记录时间戳:IP数据报在传输过程中,每经过一个路由器,路由器就将自己的IP地址及时间添加到IP数据报头内的选项字段位置。 ●宽松源路由选择:IP数据报在传输过程中,要经过IP数据报选项内列出的每个IP地址,但也可以经过其他的IP地址。 ●严格源路由选择:IP数据报在传输过程中,只能经过IP数据报选项内列出的每个IP地址。 下面我们以记录路由为例说明如何进行IP_OPTIONS选项的设置。 第一步:先声明一个数据结构,它包括选项码、选项长度、偏移量与选项数据4个字段。要注意的是,由于IP选项最长为40字节,所以所定义的结构长度不能超过这个数值。
第二步:根据要设置的选项,对说明的选项数据结构各字段进行初始化。选项码字段的值见2.3.3小节。 第三步:使用setsockopt( )函数对IP_OPTIONS选项进行设置。 以上三步对应的代码如下:
//定义一个数据结构
structip_oprion_hdr { unsignedchar code; unsignedchar length; unsignedchar offset; unsignedlong addrs[9]; }opthdr; …… //对定义的结构进行初始化
byzero((char*)&opthdr,sizeof(opthdr)); //记录路由选项码
opthdr.code=0x87; //总的选项长度
opthdr.length=39; //选项数据的初始位置
opthdr.offset=4; //设置记录路由选项
ret=setsockopt(s,IPPROTO_IP,IP_OPTIONS,(char*)&opthdr,sizeof(opthdr)); …… (2) IP_HDRINCL:该选项可以获取,也可以设置。
(3) IP_TOS:该选项可以获取,也可以设置。
(4) IP_TTL:该选项可以获取,也可以设置。
(5) IP_MULTICAST_TTL:该选项可以获取,也可以设置。
(6) IP_MULTICAST_IF:该选项可以获取,也可以设置,用于为IP多播设置一个本地接口,本地机器以后发出的任何多播数据都会经由该接口传送出去。 (7) IP_MULTICAST_LOOP:该选项可以获取,也可以设置。该选项用于控制发送的多播数据是否进入本地套接口的输入数据队列中。
(8) IP_ADD_MEMBERSHIP:该选项只能设置。该选项实际是由Winsock1提供的一个方法,可将一个套接口加入一个指定的IP多播组,此时需要用socket函数来创建地址族为AF_INET的一个套接口,同时将套接口的类型设为SOCK_DGRAM。要想将套接口加入一个多播组,要使用如下结构:
srtuctip_mreq{ structin_addr imr_multiaddr; structin_addr imr_interface; }; 在ip_mreq结构中,imr_multiaddr对应于套接口将要加入的那个多播组的二进制格式地址;而imr_interface对应于将要用来收发多播数据的一个本地接口。 (9)IP_DROP_MEMBERSHIP:该选项只能设置,用于将套接口从指定的IP组内删去,即撤销其成员资格。该选项正好与IP_ADD_MEMBERSHIP相反。使用ip_mreq结构调用该选项,并在该结构中放入与当初加入指定多播组时相同的值,套接口便会从那个组内删去,脱离成员关系。
(10) IP_DONTFRAGMENT:该选项可以获取,也可以设置,用来控制是否对IP数据报进行分段。如果设置为TRUE,IP数据报在传输过程中就不需要对IP数据报进行分段处理,当然这样就存在一个问题,当一个IP数据报的大小已经超过了最大数据传输单元(MTU)的值时,这个数据报就会被丢弃,同时向发送者返回一条ICMP错误消息,提示用户数据需要分段,但未设置分段标志位。 8.4.4IPPROTO_TCP选项级别 该选项是针对TCP协议的。在Winsock中仅有一个IPPROTO_TCP级别的选项,即TCP_NODELAY选项,该选项用来打开或关闭Nagle算法。如果该选项的值为TRUE,则在对应的套接口上禁止使用Nagle算法。在系统默认情况下,Nagle算法是打开的,该选项只适用于流式套接口(SOCK_STREAM),其地址族为AF_INET。这个选项可用在所有Winsock版本上,并得到了所有Win32平台的支持。
Nagle算法将未确认的数据存入缓冲区,直到蓄足一个包后一起发送,这样做的好处是可以减少主机发送的零碎小数据包的数目,以减少网络通信的开销,提高系统的吞吐量。但对于某些应用来说,这种算法将降低系统性能,例如交互性较强的Telnet应用程序,用户可通过它登录至一台远程机器,然后向其传送命令。通常,用户每秒只会进行少量的键击,若使用Nagle算法,便会造成响应的迟钝,甚至造成对方主机不予应答的错觉。此时,使用TCP_NODELAY选项可将此算法关闭,以适应一些交互性较强的应用程序。应用程序编写者只有在确切了解它的效果并在确实需要的情况下,才可设置TCP_NODELAY选项,因为在一般的应用中如果设置该选项,则对网络性能有明显的负面影响。 8.4.5套接口属性设置和获取实例 在本实例程序中,使用getsockopt( )函数来获取套接口的类型、接收缓冲和发送缓冲的大小,然后使用setsockopt( )函数对套接口接收缓冲进行重新设置,并用getsockopt( )函数获取重新设置以后的大小。实例程序如下:
/*************************************************************************
调试环境:VC++6.0
程序名称:socketopt.cpp
程序功能:该程序演示了getsockopt( )函数和setsockopt( ) 函数在程序中的用法 命令格式:socketopt **************************************************************************/#include<winsock2.h>#include<stdio.h>#include<stdlib.h>voidmain( ){ WSADATAwsaData; SOCKETs; //存放选项值
intoptname; //选项的长度
intoptlen;if(WSAStartup(MA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 有机蔬菜怎样种植
- 品牌策划与营销策略培训材料
- 电子商务物流时效分析对比表
- 婚姻考题复习试题含答案
- 三农信息采集与共享平台建设方案
- 农业资源整合与可持续发展解决方案
- 出版行业数字化内容管理系统设计
- 高效办公实践教程
- 通讯设备业5G基站建设与维护管理方案
- 农业科技精准种植与养殖技术推广方案
- 石塑地板铺贴施工方案
- 聚酯生产技术 聚酯工艺流程介绍
- ISO27001 信息安全管理体系培训基础知识
- 湖北省宜昌市宜都市七年级(下)期末语文试卷(含解析)
- 超声药物透入治疗
- 国家公务员考试准考证模板
- 西北大学本科学生课程成绩评分转换标准
- 固定资产盘点管理规定完整版
- 江苏扬州市梅岭小学二年级数学下册期末复习卷(一)及答案
- 旅游客源地旅游需求与预测课件
- 专升本英语阅读理解练习
评论
0/150
提交评论