【TCP/IP】地址族与数据序列 III - 字符串网络地址与网络字节序的互转

1 网络地址的初始化与分配

1.1 将字符串信息转换为网络字节序的整数型

1.2 网络地址初始化

1.3 客户端地址信息初始化

1.4 INADDR_ANY


1 网络地址的初始化与分配

1.1 将字符串信息转换为网络字节序的整数型

sockaddr_in中保存地址信息的成员为32位整数型,因此为了分配IP地址,需将其表示为32位整数型数据。

inet.h库中的函数可以帮助我们将字符串形式的IP地址转换成32位整数型数据,这个函数在转换类型的同时会附带进行网络字节序转换。

#include 
in_addr_t inet_addr(const char * string);

//成功时返回32位大端序整数型值,失败时返回INADDR_NONE。

以下是一个对这个函数使用的例子:

#include 
#include 

int main(int argc, char *argv[])
{
	char *addr1="127.212.124.78";
	char *addr2="127.212.124.256";

	unsigned long conv_addr=inet_addr(addr1);
	if(conv_addr==INADDR_NONE)
		printf("Error occured! \n");
	else
		printf("网络字节序地址: %#lx \n", conv_addr);
	
	conv_addr=inet_addr(addr2);
	if(conv_addr==INADDR_NONE)
		printf("Error occureded \n");
	else
		printf("网络字节序地址: %#lx \n\n", conv_addr);
	return 0;
}

运行结果:

从运行结果可以看出,inet_addr函数不仅可以把IP地址转成32位整数型,而且可以检测无效
的IP地址
。另外从输出结果可以验证函数协助完成了转换网络字节序。

接下来就是inet_aton函数了,这个函数与inet_addr函数在功能上完全相同,也将字符串IP地址转换为32位网络字节序整数并返回,但该函数可以直接将字节序传入到in_addr结构体。

#include 

int inet_aton(const char * string, struct in_addr * addr);
    
//  一步成功时返回1(true),失败时返回0(false) 
//  string 含有需转换的IP地址信息的字符串地址值
//  addr 将保存转换结果的in_addr结构体变量的地址值
    

在编程中若调用的是inet_addr函数,则需将转换后的IP地址带入到sockaddr_in结构体中声明的in_addr结构体变量。而inet_aton函数则不需此过程。(注意!!这个函数在Windows中不存在)

代码例子:

#include 
#include 
#include 
void error_handling(char *message);

int main(int argc, char *argv[])
{
	char *addr="127.232.124.79";
	struct sockaddr_in addr_inet;
	
	if(!inet_aton(addr, &addr_inet.sin_addr))
		error_handling("Conversion error");
	else
		printf("网络字节序地址: %#x \n", addr_inet.sin_addr.s_addr);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

最后,还有一个与inet_aton函数相反的函数,这个函数可以把网络字节序整数型IP地址转换成为字符串形式。

#include 

char * inet_ntoa(struct in_addr adr) 

//成功时返回转换的字符串地址值,失败时返回-1

该函数将通过参数传入的整数型IP地址转换为字符串格式并返回 。但调用时返回值类型为char指针。返回字符串地址意味着字符串已保存到内存空间,但该函数并未开辟持久的内存空间将数据进行存放 。也就是说,调用完该函数后,应立即将字符串信息复制到其他内存空间。因为若再次调用inet_ntoa函数,则有可能覆盖之前保存的字符串 。若需要长期保存,则应将字符串复制到其他内存空间。下面给出该函数调用示例:

#include 
#include 
#include 

int main(int argc, char *argv[])
{
	struct sockaddr_in addr1, addr2;
	char *str_ptr;
	char str_arr[20];
   
	addr1.sin_addr.s_addr=htonl(0x1020304);
	addr2.sin_addr.s_addr=htonl(0x1010101);
	
	str_ptr=inet_ntoa(addr1.sin_addr);
	strcpy(str_arr, str_ptr);
	printf("点分十进制网络地址1: %s \n", str_ptr);
	
	inet_ntoa(addr2.sin_addr);
	printf("点分十进制网络地址2: %s \n", str_ptr);
	printf("点分十进制网络地址3: %s \n", str_arr);
	return 0;
}

运行结果:

1.2 网络地址初始化

套接字创建过程中常见的网络地址信息初始化流程

【TCP/IP】地址族与数据序列 III - 字符串网络地址与网络字节序的互转_第1张图片

1.3 客户端地址信息初始化

上述网络地址信息初始化过程主要针对服务器端而非客户端。给套接字分配IP地址和端口号
主要是为下面这件事做准备 :

“请把进入IP 211 .217.168.13 、9190端口的数据传给我 ! "

而客户端中连接请求如下 :

“请连接到 IP 211.217.168.13、9190端口!”

请求方法不同意味着调用的函数也不同。服务器端的准备工作通过bind 函数完成,而客户端则通过connect 函数完成 。 因此,函数调用前需准备的地址值类型也不同 。服务器端声明sockaddr_in结构体变量,将其初始化为赋予服务器端IP和套接字的端口号,然后调用bind函数;而客户端则声明sockaddr_in结构体, 并初始化为要与之连接的服务器端套接字的IP和端口号,然后调用connect函数。 

1.4 INADDR_ANY

 每次创建服务器端套接字都要输入IP地址会有些繁琐,此时可用以下初始化地址方式。

【TCP/IP】地址族与数据序列 III - 字符串网络地址与网络字节序的互转_第2张图片

与之前方式最大的区别在于:利用常数lNADDR ANY分配服务器端的IP地址,则可自动获取运行服务器端的计算机IP地址,不必亲自输入若同一计算机中已分配多个IP地址(多宿主 Multi-homed 计算机, 一般路由器属于这一类) ,则只要端口号一致,就可以从不同 IP地址接收数据 。因此,服务器端中优先考虑这种方式。而客户端中除非带有一部分服务器端功能,否则一般不会采用这种方式。

你可能感兴趣的:(网络编程,tcp/ip,网络,笔记,网络协议)