TCP/IP网络编程笔记-ch3.地址族与数据序列

函数

//主机字节序与网络字节序的转换
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);

//IP地址字符串与32位整数型数据的转换
    //IP address to network
    in_addr_t inet_addr(const char* string);//IP地址字符串=>32位整数型数据  返回32位整数型数据 失败返回INADDR_NONE
    int inet_aton(const char *string,struct in_addr *addr);//IP地址字符串=>32位整数型数据(存放在结构体in_addr的addr中) 返回执行结果(1:成功 0:失败)
    
    //network to IP address
    char * inet_ntoa(struct in_addr ad);//返回转换的字符串地址值 失败返回-1

地址信息结构

sockaddr_in结构

定义:
struct sockaddr_in{
    sa_family_t         sin_family;//地址族(address family)
    uint16_t            sin_port;//16位TCP/UDP端口号
    struct in_addr      sin_addr;//32位IP地址
    char                sin_zero[8];//不使用
};
struct in_addr{
    In_addr_t           s_addr;//32位IPv4地址
}

使用:
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;  //设置地址家族
serv_addr.sin_port = htons(argv[1]);  //设置端口
serv_addr.sin_addr.s_addr = htons(atoi[argv[2]);  //设置地址

htons(host to network short):将端口号由主机字节序转换为网络字节序的整数值。
//h:host    n:network   s:short

uint16_t、in_addr_t等类型可参考POSIX(Portable Operating System Interface,可移植操作系统接口)
POSIX是为UNIX系列操作系统设立的标准,它定义了一些其他数据类型如:

数据类型名称数据类型说明声明的头文件
int8_tsigned 8-bit intsys/types.h
uint8_tunsigned 8-bit int(unsigned char)sys/types.h
int16_tsigned 16-bit intsys/types.h
uint16_tunsigned 16-bit int(unsigned short)sys/types.h
int32_tsigned 32-bit intsys/types.h
uint32_tunsigned 32-bit int(unsigned long)sys/types.h
sa_family_t地址族(address family)sys/socket.h
socklen_t长度(length of struct)sys/socket.h
in_addr_tIP地址,声明为uint32_tnetinet/in.h
in_port_t端口号,声明为uint16_tnetinet/in.h

sockadr_in变量地址值传递给bind函数:

struct sockaddr_in serv_addr;
...
if(bind(serv_sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr))==-1)
    error_handling("bind() error");
    
sockaddr结构体:
struct sockaddr{
    sa_family_t sin_family;//地址族(Address Family)
    char        sa_data[14];//地址信息
};
sa_data: 需包含IP地址和端口号,剩余部分填充0,此为bind函数要求。这对于包含地址信息而言很麻烦,所以才有了新的结果欧体sockaddr_in
即符合bind函数要求的字节流


sockaddr_in成员分析

sin_family:

每种协议族适用地址族均不同。如IPv4使用4字节地址族,IPv6使用16字节地址族,参考表:

地址族(Address Family)含义
AF_INETIPv4网络协议中使用的地址族
AF_INET6IPv6网络协议中使用的地址族
AF_LOCAL本地通信中采用的UNIX协议的地址族
sin_port:

保存16位端口号,重点为,以网络字节序保存。

sin_addr:

保存32位IP地址信息,且也以网络字节序保存。

sin_zero:

无特殊含义,是为了使结构体sockaddr_in大小与sockaddr结构体保持一致而插入的成员。需填充为0

网络字节序与地址变换

网络字节序

CPU保存数据的方式有两种:
大端序(Big Endian):高位字节存放到低位地址
小端序(Little Endian):高位字节存放到高位地址

在通过网络传输数据时约定统一方式,这种约定称为网络字节序(Network Byte Order),非常简单:统一为大端序。(先将数据数组转化为大端序格式再进行网络传输。

地址变换

unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
h:host n:network s:short l:long
ntonhs:把short型数据从网络字节序转化为主机字节序
主机字节序:可能为小端序,可能为大端序 由主机决定
网络字节序:统一为大端序
例:
unsigned long host_addr=0x12345678;
unsigned long net_addr=htonl(host_addr);//0x78563412   (说明本机CPU为小端CPU)(Intel和AMD系列的CPU都采用小端序标准)

网络地址的初始化和分配

inet_addr

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

#include<arpa/inet.h>
in_addr_t inet_addr(const char* string);
//成功返回32位大端序整数型值,失败返回INADDR_NONE

例:
char *addr1="1.2.3.4";
char *addr2="1.2.3.256";

unsigned long conv_addr=inet_addr(addr1);//结果:0x4030201
conv_addr=inet_addr(addr2);              //结果:INADDR_NONE

inet_aton

在功能上与inet_addr完全相同,将字符串形式IP地址转换为32位网络字节序整数并返回,但该函数利用in_addr结构体,使用频率更高。

#include<arpa/inet.h>
int inet_aton(const char *string,struct in_addr *addr);
//成功返回1(true),失败返回0(false)

例:
char *addr="127.232.124.79";
struct sockaddr_in addr_inet;
if(inet_aton(addr,&addr_inet.sin_addr)//如果转换成功
{
    //结果addr_inet.sin_addr.s_addr:0x4f8ce87f
}

inet_ntoa

#include<arpa/inet.h>
char *inet_ntoa(struct in_addr adr);
//成功返回转换的字符串地址值,失败返回-1

例:
struct sockaddr_in addr1;
addr1.sin_addr.s_addr=htol(0x1020304);
char *str_ptr=inet_ntoa(addr1.sin_addr);//结果1.2.3.4

网络地址初始化

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

struct sockaddr_in addr;
char *serv_ip="211.217.168.13";         //声明IP地址字符串
char *serv_port="9190";                 //声明端口号字符串
memset(&addr,0,sizeof(addr));           //结构体变量addr的所有成员初始化为0
addr.sin_family=AF_INET;                    //指定协议族
addr.sin_addr.s_addr=inet_addr(serv_ip);    //基于字符串的IP地址初始化
addr.sin_port=htons(atoio(serv_port));      //基于字符串的端口号初始化

//addr.sin_addr.s_addr可赋值为INADDR_ANY:自动获取运行服务器端的计算机IP地址,不必亲自输入。
//若同一计算机中分配多个IP地址,只要端口号一致,可从不同IP地址接收数据。故服务器端中优先考虑此方式。
//客户端除非带有一部分服务器端功能,否则不会采用。

实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhyiXOTp-1641630596807)(https://note.youdao.com/yws/res/2/WEBRESOURCEdb1b090fb4e8b7ec3ef6aa993818ef62)]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值