您的位置:首页 > 理论基础 > 计算机网络

《ASCE1885的网络编程》---Winsock APIの网络信息获取函数

2010-07-24 15:26 567 查看
网络中的主机需要安装TCP/IP协议或其他协议才能进行通信,网络应用程序有时需要获取主机上或网络有关的信息,这些信息一般存放在数据文件中。如Unix系统中,主机名存放在/etc/hosts文件中,网络信息则存放在etc/networks文件中,因此这类获取主机上与网络有关的信息的函数也叫数据库函数。

与网络有关的信息主要分为4大类:

主机信息:函数名一般以gethostby开头,在程序中较多使用;

网络信息:函数名一般以getnetby开头,在程序中较少使用;

协议信息:函数名一般以getprotoby开头,在程序中较少使用;

服务信息:函数名一般以getservby开头,在程序中较多使用。

1)获得主机名---gethostname()

gethostname()函数用来获得一台主机的名称信息:

int gethostname(

__out char *name, //一个指向将要存放主机名的缓冲区的指针

__in int namelen //缓冲区的长度

);

如果函数调用成功,则返回0;如果调用失败,则返回SOCKET_ERROR错误信息。可以通过调用WSAGetLastError()来得到一个特定的错误代码,错误代码说明如下:

WSAEFAULT //名字长度参数太小

WSANOTINITIALISED //在应用这个API前,必须成功调用WSAStartup()

WSAENETDOWN //Windows Sockets实现检测到了网络子系统的错误

WSAEINPROGRESS //一个阻塞Windows Sockets操作正在进行

该函数把本地主机名存放入由name参数指定的缓冲区。主机名的形式取决于Windows Sockets系统的实现,它可能是一个简单的主机名,或者是一个域名。不管是哪种形式,该函数返回的名字必定可以在gethostbyname()和WSAAsyncGetHostByName()函数中使用。

2)获得与套接字相连的远程协议地址---getpeername()

getpeername()函数格式如下:

int getpeername(

__in SOCKET s, //一个已经建立连接的套接字描述字

__out struct sockaddr *name, //指向返回的远程协议地址

__inout int *namelen //远程协议地址长度

);

函数调用成功,返回0;调用失败,则返回SOCKET_ERROR错误信息,可以调用WSAGetLastError()函数来获取对该错误的进一步描述,错误代码如下:

WSANOTINITIALISED //在使用此函数前应成功调用WSAStartup()

WSAENETDOWN //Windows套接字实现检测到网络子系统失效

WSAEFAULT //namelen参数不够大

WSAEINPROGRESS //一个阻塞Windows套接口调用正在进行中

WSAENOTCONN //套接口未建立连接

WSAENOTSOCK //描述字不是一个套接口

getpeername()函数用于从套接口s中获取与它绑定的远程协议的地址信息,并将它存放在sockaddr类型的name结构中。它只能用于已经建立连接的套接口。对于数据报类型的套接口来说,它只能返回先前调用connect()函数时使用的对等端信息,在sendto()函数中使用过的对等端信息不能被返回。

3)获得套接口本地协议地址---getsockname()

getsockname()函数的格式如下:

int getsockname(

__in SOCKET s, //标识一个套接口描述字

__out struct sockaddr *name, //指向返回的本地协议地址的指针

__inout int *namelen //本地协议地址长度,当函数调用完成后,它可以返回实际的本地地址长度

);

调用成功返回0,失败则返回SOCKET_ERROR错误信息,可以通过调用WSAGetLastError()函数获取进一步错误描述。错误代码如下:

WSANOTINITIALISED //在使用此API之前应成功调用WSAStartup()

WSAENETDOWN //Windows套接口实现检测到网络子系统失效

WSAEFAULT //namelen参数不够大

WSAEINPROGRESS //一个阻塞的Windows套接口调用正在进行中

WSAENOTSOCK //描述字不是一个套接口

getsockname()函数用于获取一个套接口的协议地址,它用于一个已绑定或已连接套接口。本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。

若一个套接口与INADDR_ANY绑定,即该套接口可以用任意的主机地址,此时除非调用connect()或accept()来连接,否则getsockname()将不会返回主机IP地址的任何信息。

除非套接口被连接,Windows套接口应用程序不应假设IP地址会从INADDR_ANY编程其他地址。这是因为对于一个有多个IP地址的主机来说,除非套接口被连接,否则该套接口所用的IP地址是不可知的(即不能确定是哪一个)。

4)根据主机名取得主机信息---gethostbyname()或WSAAsyncGetHostByName()

这两个Winsock API函数从主机数据库取回与指定的主机名对应的主机信息。这两个函数均返回一个hostent结构型的变量:

typedef struct hostent {

char FAR *h_name; //正式的主机名

char FAR FAR **h_aliases; //二维字符指针,返回一台主机的所有别名(即别名列表)

short h_addrtype; //主机地址类型,如AF_INET表示IPv4地址

short h_length; //可以返回主机地址的字节数

char FAR FAR **h_addr_list; //返回一台主机的所有IP地址。这个数组中的每个地址都是

//按网络字节顺序返回的。一般情况下,应用程序都采用该数组的第一个地址。

//但是如果返回的地址不止一个,应用程序就会相应地选择一个最恰当的地址,

//而不是一直都用第一个地址

} HOSTENT, *PHOSTENT, FAR *LPHOSTENT;

在Winsock1中提供的gethostbyname()函数格式如下:

struct hostent* FAR gethostbyname(

__in const char *name //一个指向主机名的指针

);

在Winsock1中提供的异步扩展WSAAsyncGetHostByName()函数的格式是:

HANDLE WSAAsyncGetHostByName(

__in HWND hWnd, //一个窗口句柄,表示异步请求完成时,该窗口句柄应该收到一条消息

__in unsigned int wMsg, //当异步请求完成时,将要接收的消息

__in const char *name, //指向主机名的指针

__out char *buf, //接收hostent数据的数据区指针。该数据区必须大于hostent结构的大小,这是因为

//Windows Sockets实现不仅要用该数据区容纳hostent结构,而且hostent结构的成员引用的所有

//数据也要在该区域内。建议用户提供一个MAXGETHOSTSTRUCT字节大小的缓冲区

__in int buflen //buf的大小

);

调用成功,gethostbyname()函数返回hostent结构的指针,调用失败则返回一个空指针,调用WSAGetLastError()得到特定的错误代码:

WSANOTINITIALISED //应用这个API前,必须成功调用WSAStartup()

WSAENETDOWN //Windows Sockets实现检测到了网络子系统的错误

WSAHOST_NOT_FOUND //没有找到授权应答的主机

WSATRY_AGAIN //没有找到非授权主机,或者服务器故障(SERVERFAIL)

WSANO_RECOVERY //无法恢复的错误,如查询格式错误(FORMERR)、拒绝服务(REFUSED)

WSANO_DATA //有效的名字,但没有关于请求类型的数据记录

WSAEINPROGRESS //一个阻塞的Windows Sockets操作正在进行

WSAEINTR //阻塞调用被WSACancelBlockingCall()取消了

WSAAsyncGetHostByName()函数是gethostbyname()函数的Windows异步扩展函数。所谓异步,指的是Windows Sockets的实现启动该操作后立即回到调用方,并传回一个异步任务句柄,应用程序可以用它来标识该操作。

当异步操作完成时,如果成功则将主机名和地址信息拷贝到buf缓冲区中,同时向句柄为hWnd的应用程序窗口发送一条消息(wMsg)。wParam参数包含了初次函数调用时返回的异步任务句柄,lParam的高16位包含着错误代码。

错误代码为0说明异步操作成功,在成功完成的情况下,提供给初始函数调用的缓冲区中包含额一个hostent结构。

错误代码为WSAENOBUFS,则说明初始调用时有buflen指出的缓冲区大小太小;在这种情况下,lParam的低16位提供所有信息所需的缓冲区大小。

错误代码和缓冲区大小应使用WSAGETASYNCERROR和WSAGETASYNCBUFLEN宏从lParam中取出。这两个宏定义为:

#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam)

#define WSAGETASYNCERROR(lParam) HIWORD(lParam)

使用这些宏可以最大限度的提供程序源代码的可移植性。

函数的返回值指出异步操作是否成功启动,注意它并不隐含操作本身成功与否。若操作成功,则WSAAsyncGetHostByName()返回一个HANDLE类型的非0值,它用来标识该异步请求任务的句柄。通过该句柄使用WSACancelAsyncRequest()函数可取消该操作,也可通过检查wParam消息参数,以匹配异步操作和完成消息。如果异步操作不能启动,WSAAsyncGetHostByName()返回一个0值,使用WSAGetLastError()得到下面错误代码:

WSANOTINITIALISED //在使用本API前必须进行一次成功的WSAStartup()调用

WSAENETDOWN // Windows Sockets实现检测到了网络子系统的错误

WSAEINPROGRESS //一个阻塞的Windows Sockets操作正在进行

WSAEWOULDBLOCK //本异步操作此时由于Windows Sockets实现的资源或其他限制的制约而无法调度

在应用程序的窗口收到消息时可能会设置下列错误代码,它们可以通过WSAGETASYNCERROR宏从应答的消息lParam中取出:

WSAENETDOWN // Windows Sockets实现检测到了网络子系统的错误

WSAENOBUFS //可用的缓冲区空间不足或没有

WSAHOST_NOT_FOUND //未找到授权应答主机

WSATRY_AGAIN //没有找到非授权主机,或者服务器故障(SERVERFAIL)

WSANO_RECOVERY //不可恢复性错误

WSANO_DATA //无请求类型的数据记录

实例代码如下:

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <windows.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char **argv)

{

//-----------------------------------------

// Declare and initialize variables

WSADATA wsaData;

int iResult;

DWORD dwError;

int i = 0;

struct hostent *remoteHost;

char *host_name;

struct in_addr addr;

char **pAlias;

// Validate the parameters

if (argc != 2) {

printf("usage: %s hostname/n", argv[0]);

printf(" to return the IP addresses for the host/n");

printf(" %s www.contoso.com/n", argv[0]);

printf(" or/n");

printf(" %s IPv4string/n", argv[0]);

printf(" to return an IPv4 binary address for an IPv4string/n");

printf(" %s 127.0.0.1/n", argv[0]);

return 1;

}

// Initialize Winsock

iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (iResult != 0) {

printf("WSAStartup failed: %d/n", iResult);

return 1;

}

host_name = argv[1];

printf("Calling gethostbyname with %s/n", host_name);

remoteHost = gethostbyname(host_name);

if (remoteHost == NULL) {

dwError = WSAGetLastError();

if (dwError != 0) {

if (dwError == WSAHOST_NOT_FOUND) {

printf("Host not found/n");

return 1;

} else if (dwError == WSANO_DATA) {

printf("No data record found/n");

return 1;

} else {

printf("Function failed with error: %ld/n", dwError);

return 1;

}

}

} else {

printf("Function returned:/n");

printf("/tOfficial name: %s/n", remoteHost->h_name);

for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) {

printf("/tAlternate name #%d: %s/n", ++i, *pAlias);

}

printf("/tAddress type: ");

switch (remoteHost->h_addrtype) {

case AF_INET:

printf("AF_INET/n");

break;

case AF_NETBIOS:

printf("AF_NETBIOS/n");

break;

default:

printf(" %d/n", remoteHost->h_addrtype);

break;

}

printf("/tAddress length: %d/n", remoteHost->h_length);

i = 0;

if (remoteHost->h_addrtype == AF_INET)

{

while (remoteHost->h_addr_list[i] != 0) {

addr.s_addr = *(u_long *) remoteHost->h_addr_list[i++];

printf("/tIP Address #%d: %s/n", i, inet_ntoa(addr));

}

}

else if (remoteHost->h_addrtype == AF_NETBIOS)

{

printf("NETBIOS address was returned/n");

}

}

return 0;

}

5)根据主机地址取得主机信息---gethostbyaddr()或WSAAsyncGetHostByAddr()

这两个函数可以根据主机的IP地址取得主机名和主机地址等信息。

在Winsock1中提供的gethostbyaddr()函数的格式是:

struct hostent* FAR gethostbyaddr(

__in const char *addr, //指向网络字节顺序地址的指针

__in int len, //地址的长度,如果是IPv4类型的地址,则该值是4

__in int type //地址类型,如AF_INET

);

在Winsock1中提供的异步扩展WSAAsyncGetHostByAddr()函数的格式是:

HANDLE WSAAsyncGetHostByAddr(

__in HWND hWnd, //窗口句柄,表示当异步请求完成时,该窗口句柄应该收到一个消息

__in unsigned int wMsg, //当异步请求完成后,将要接收的消息

__in const char *addr, //指向网络字节顺序地址的指针

__in int len, //地址的长度,如果是IPv4类型的地址,则该值是4

__in int type, //地址类型,如AF_INET

__out char *buf, //接收hostent数据的数据区指针

__in int buflen //buf的大小

);

返回信息同4)。

实例如下:

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

int main(int argc, char **argv)

{

//-----------------------------------------

// Declare and initialize variables

WSADATA wsaData;

int iResult;

DWORD dwError;

int i = 0;

int bIpv6 = 0;

struct hostent *remoteHost;

char *host_addr;

struct in_addr addr = { 0 };

IN6_ADDR addr6;

char **pAlias;

// Validate the parameters

if (argc < 2) {

printf("usage: %s 4 ipv4address/n", argv[0]);

printf(" or/n");

printf("usage: %s 6 ipv6address/n", argv[0]);

printf(" to return the hostname/n");

printf(" %s 4 127.0.0.1/n", argv[0]);

printf(" %s 6 0::1/n", argv[0]);

return 1;

}

// Validate parameters

if (atoi(argv[1]) == 4)

bIpv6 = 0;

else if (atoi(argv[1]) == 6)

bIpv6 = 1;

else {

printf("usage: %s 4 ipv4address/n", argv[0]);

printf(" or/n");

printf("usage: %s 6 ipv6address/n", argv[0]);

printf(" to return the hostname/n");

printf(" %s 4 127.0.0.1/n", argv[0]);

printf(" %s 6 0::1/n", argv[0]);

return 1;

}

// Initialize Winsock

iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

if (iResult != 0) {

printf("WSAStartup failed: %d/n", iResult);

return 1;

}

host_addr = argv[2];

printf("Calling gethostbyaddr with %s/n", host_addr);

if (bIpv6 == 1) {

{

iResult = inet_pton(AF_INET6, host_addr, &addr6);

if (iResult == 0) {

printf("The IPv6 address entered must be a legal address/n");

return 1;

} else

remoteHost = gethostbyaddr((char *) &addr6, 16, AF_INET6);

}

} else {

addr.s_addr = inet_addr(host_addr);

if (addr.s_addr == INADDR_NONE) {

printf("The IPv4 address entered must be a legal address/n");

return 1;

} else

remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET);

}

if (remoteHost == NULL) {

dwError = WSAGetLastError();

if (dwError != 0) {

if (dwError == WSAHOST_NOT_FOUND) {

printf("Host not found/n");

return 1;

} else if (dwError == WSANO_DATA) {

printf("No data record found/n");

return 1;

} else {

printf("Function failed with error: %ld/n", dwError);

return 1;

}

}

} else {

printf("Function returned:/n");

printf("/tOfficial name: %s/n", remoteHost->h_name);

for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) {

printf("/tAlternate name #%d: %s/n", ++i, *pAlias);

}

printf("/tAddress type: ");

switch (remoteHost->h_addrtype) {

case AF_INET:

printf("AF_INET/n");

break;

case AF_INET6:

printf("AF_INET6/n");

break;

case AF_NETBIOS:

printf("AF_NETBIOS/n");

break;

default:

printf(" %d/n", remoteHost->h_addrtype);

break;

}

printf("/tAddress length: %d/n", remoteHost->h_length);

if (remoteHost->h_addrtype == AF_INET) {

while (remoteHost->h_addr_list[i] != 0) {

addr.s_addr = *(u_long *) remoteHost->h_addr_list[i++];

printf("/tIPv4 Address #%d: %s/n", i, inet_ntoa(addr));

}

} else if (remoteHost->h_addrtype == AF_INET6)

printf("/tRemotehost is an IPv6 address/n");

}

return 0;

}

6)根据协议名取得主机协议信息---getprotobyname()或WSAAsyncGetProtoByName()

函数getprotobyname()和WSAAsyncGetProtoByName()可以根据协议名称返回对应的相关协议信息,它们都要使用一个与协议有关的结构:

typedef struct protoent {

char FAR *p_name; //正式协议名

char FAR FAR **p_aliases; //二维字符指针,返回一个协议的所有别名

short p_proto; //以主机字节顺序排列的协议号

} protoent;

在Winsock1中提供的getprotobyname()函数格式是:

struct PROTOENT* FAR getprotobyname(

__in const char *name //指向协议名的指针

);

在Winsock1中提供的异步扩展WSAAsyncGetProtoByName()函数格式是:

HANDLE WSAAsyncGetProtoByName(

__in HWND hWnd, //窗口句柄,表示当异步请求完成时,该窗口句柄应该收到一个消息

__in unsigned int wMsg, //当异步请求完成后,将要接收的消息

__in const char *name, //指向协议名的指针

__out char *buf, //接收protoent数据的缓冲区指针

__out int buflen //buf的大小

);

返回信息类似WSAAsyncGetHostByName()。

7)根据协议号取得主机协议信息---getprotobynumber()或WSAAsyncGetProtoByNumber()

这两个函数返回对应于给定协议号的相关协议信息。

在Winsock1中提供的getprotobynumber()函数的格式是:

struct PROTOENT* FAR getprotobynumber(

__in int number //一个以主机字节顺序排列的协议号

);

在Winsock1中提供的异步扩展WSAAsyncGetProtoByNumber()函数的格式是:

HANDLE WSAAsyncGetProtoByNumber(

__in HWND hWnd,

__in unsigned int wMsg,

__in int number, //一个以主机字节顺序排列的协议号

__out char *buf,

__in int buflen

);

8)根据服务名取得相关服务信息---getservbyname()或WSAAsyncGetServByName()

这两个函数用于返回对应于给定服务名和协议名的相关服务信息,它们都用到如下的结构:

typedef struct servent {

char FAR *s_name; //正式的服务名

char FAR FAR **s_aliases; //所有其他的可选服务别名

short s_port; //连接该服务时需要用到的端口号,返回的端口号是以网络字节顺序排列的

char FAR *s_proto; //连接该服务时用到的协议名

} SERVENT, *PSERVENT, FAR *LPSERVENT;

在Winsock1中提供的getservbyname()函数格式是:

struct servent* FAR getservbyname(

__in const char *name, //一个指向服务名的指针

__in const char *proto //指向协议名的指针(可选)。如果这个指针为空,getservbyname()返回

//第一个name与s_name或者某一个s_aliases匹配的服务条目。否则,getservbyname()对name

//和proto都进行匹配

);

在Winsock1中提供的异步扩展WSAAsyncGetServByName()函数的格式是:

HANDLE WSAAsyncGetServByName(

__in HWND hWnd,

__in unsigned int wMsg,

__in const char *name,

__in const char *proto,

__out char *buf,

__in int buflen

);

9)根据端口号取得相关服务信息---getservbyport()或WSAAsyncGetServByPort()

这两个函数用于返回对应于给定端口号和协议名的相关服务信息。

在Winsock1中提供的getservbyport()函数的格式是:

struct servent* FAR getservbyport(

__in int port, //给定的端口号,以网络字节顺序排列

__in const char *proto //指向协议名的指针(可选)。如果这个指针为空,getservbyport()

//返回第一个port与s_port匹配的服务条目;否则,getservbyport()对port和proto都进行匹配

);

在Winsock1提供的异步扩展WSAAsyncGetServByPort()函数的格式是:

HANDLE WSAAsyncGetServByPort(

__in HWND hWnd,

__in unsigned int wMsg,

__in int port,

__in const char *proto,

__out char *buf,

__in int buflen

);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: