CC BY 4.0 (除特别声明或转载文章外)
如果这篇博客帮助到你,可以请我喝一杯咖啡~
地址族与数据序列
一、分配给套接字的IP地址和端口号
ip地址分为两类:
-
IPv4:4字节地址族
-
IPv6:16字节地址族(为解决2010年时IP地址快要耗尽时提出的标准)
IPv4标准的4字节IP地址分为网络地址和主机地址,且分为ABCDE等类型,一般不会使用已被预约的E类地址。
首先将数据传到主机的网络(网络地址(网络ID))(路由器或交换机),然后再根据主机地址(主机ID)找到目标计算机。
端口号:端口号是同一操作系统内为区分不同套接字而设置的,不能将1个端口号分配给不同的套接字。
端口号由16位构成,范围为0-65535。0-1023是知名端口,一般分配给特定的应用程序。
虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复。
例如,某TCP套接字使用9190端口,其他TCP套接字不能用9190端口,但UDP套接字可以使用。
二、地址信息的表示
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地址
};
POSIX:可移植操作系统接口
struct sockaddr_in serv_addr;
if(bind(serv_sock,(struct sockaddr*) &serv_addr,sizeof(serv_addr))==-1) {
error_handling("bind() error!");
}
//第一个参数为要分配IP地址和端口号的套接字文件描述符
//第二个参数为sockaddr结构体变量地址值
//第三个参数为第二个结构体变量的长度
struct sockaddr
{
sa_family_t sin_family; //地址族
char sa_data[14]; //地址信息
}
//sa_data中应该包含IP地址和端口号,共6字节,剩下的八字节sockaddr_in中sin_zero不使用,填0。
三、网络字节序与地址变换
-
字节序与网络字节序
CPU向内存保存数据的方式有两种,同时,CPU解析数据的方式也有两种。
大端序:高位字节存放在低位地址
小端序:高位字节存放在高位地址
网络字节序统一为大端序。
Intel和AMD的CPU都采用小端序标准。
1)大端模式:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
(其实大端模式才是我们直观上认为的模式,和字符串存储的模式差类似)
低地址 ——————–> 高地址 0x12 | 0x34 | 0x56 | 0x78
2)小端模式:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
低地址 ——————–> 高地址 0x78 | 0x56 | 0x34 | 0x12
-
字节序转换
unsigned short htons(unsigned short); unsigned short ntohs(unsigned short); unsigned long htonl(unsigned long); unsigned long ntohl(unsigned long);
其中,htons,h代表主机字节序,n表示网络字节序,htons,可以看做讲主机字节序转换为网络字节序,数据类型为short。
四、网络地址的初始化和分配
-
将字符串信息转换为网络字节序的整数型
#include <arpa/inet.h> in_addr_t inet_addr(const char * string); //成功时返回32位大端序整数型值,失败时返回INADDR_NONE int inet_aton(const char * string, struct in_addr * addr); // string : 含有需要转换的IP地址信息的字符串地址值 // addr : 将保存转换结果的in_addr结构体变量的地址值,自动将结果保存到了addr结构体变量 char * inet_ntoa(struct in_addr adr); //成功时返回转换的字符串地址值,失败时返回-1.
-
网络地址初始化
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_addr.s_addr = htonl(INADDR_ANY); //利用常数INADDR_ANY分配服务器端的IP地址 addr.sin_port = htons(atoi(serv_port)); //基于字符串的端口号初始化
3.向套接字分配网络地址
int bind(int sockfd,struct sockaddr * myaddr,socklen_t addrlen);
2后初始化后再绑定(bind)就好。