作者:刘磊 2020.4.24 参考书目:《Windows网络编程》刘琰等著
一、套接字是什么
Windows Sockets是Windows环境下的网络编程接口,最初源于UNIX环境下的BSD Socket,是一个与网络协议无关的编程接口。
Windows 套接字为程序员提供了一套简单的API,Windows Sockets定义了程序员能够使用并且网络软件供应商能够实现的一套库函数调用和相关语义。
Windows Sockets API是Windows提供给基于套接字的网络应用程序开发的接口。
二、Sockets编程接口
三、Windows Sockets DLL的初始化和释放
使用任何Windows Sockets API调用前,必须先调用启动函数WSAStartup()来完成Windows Sockets DLL的初始化,目的是:协商版本支持,分配必要资源。完成对Windows Sockets DLL的使用后,必须调用函数WSACleanup()来实现释放为自己分配的资源。
1、WSAStartup()函数
函数原型:
WSAStartup(
_in wVersionRequested,
_out lpWSAData
);
参数说明:
wVersionRequested[in]: Windows Sockets API版本号
lpWSAData[out]: 指向WSADATA数据结构的指针,用来接收Windows Sockets实现细节。
返回值:
成功 - 0
失败 - 返回错误码
具体操作:
第一步:创建类型为WSADATA的对象。
WSADATA wsaData;
第二步:调用函数WSAStartup(),并根据返回值判断错误信息。
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
PS:MAKEWORD(a, b)是将两个byte型合并成一个word型,b在高8位,a在低8位。例如,a = 2 = 0000 0010, b = 1 = 0000 0001,合起来就是 1 0000 0010
2、WSACleanup()函数
每一次WSAStartup()函数启动,必须对应一个WSACleanup()释放。
函数原型:
int WSACleanup(void);
返回值:
成功 - 0
失败 - 返回错误码
具体操作:
int iResult;
iResult = WSACleanup();
if (iResult != 0)
{
printf("WSACleanup failed: %d\n", iResult);
return 1;
}
四、获取主机IP地址
基本步骤:
第一步:调用WSAStartup()函数进行初始化。
第二步:调用gethostname()获取主机名称.
第三步:调用gethostbyname()获取主机信息。
第四步:调用WSACleanup()函数进行资源释放。
gethostbyname(host_name)返回hostent结构/体,该结构体定义如下:
struct hostent {
char FAR * h_name; /*地址名*/
char FAR * FAR * h_aliases; /*主机别名*/
short h_addrtype; /*地址类型,通常是AF_INET*/
short h_length; /*地址的字节长度*/
char FAR * FAR * h_addr_list;/*地址表,以网络字节序表示*/
};
五、代码如下:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib");
int main(int argc, char **argv){
// 声明和初始化变量
WSADATA wsaData;
int iResult; DWORD dwError; int i = 0;
struct hostent *remoteHost;
char host_name[256];
struct in_addr addr;
char **pAlias;
//初始化Windows Sockets
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
//查找主机名
iResult = gethostname(host_name, sizeof(host_name));
if (iResult != 0)
{
printf("gethostname failed: %d\n", iResult);
return 1;
}
//根据主机名获得主机信息
remoteHost = gethostbyname(host_name);
printf("Calling gethostbyname with %s\n", 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);
// 如果返回的是IPv4的地址, 则输出 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;
}