c++网络编程基础(二)
一.大端序小端序
如果数据字节占用内存大小超过1字节,那么CPU数据存储在内存中有两种方式:
大端序(Big Endian):低位字节存放在高位,高位字节存放在低位;
小端序(Little Endian):低位字节存放在低位,高位字节存放在高位;
假设从内存0x00000001开始存储十六位进制数0x12345678那么
大端序:
0x00000001 0x12
0x00000002 0x34
0x00000003 0x56
0x00000004 0x78
小端序:
0x00000001 0x78
0x00000002 0x56
0x00000003 0x34
0x00000004 0x12
在我们平常中正常是使用大端序来对齐大多为英特尔cpu。
操作文件的本质是把内存中的数据写入磁盘,在网络编程中,传输数据的本质也是把数据写入文件。
大小端序主要是在不同设备之间传输数据可能会造成问题。
在网络编程中,数据收发时有自动转化机制,不需要程序员手动转换,只有向sockaddr_in结构体成员变量填充数据时,才需要考虑字节问题。
二.网络字节序
为了解决不同设备之间的数据传输问题,采用网络字节序(大端序)。
c语言提供了四个函数,用于在主机字节序和网络字节序之间进行切换:
1 | uint16_t htons(uint16_t hostshort); //2字节整数 |
h:host (主机)
to:转换
n:network (网络)
s:short (2字节 16位的整数)
l:long (4字节 32位整数)
三.IP地址和通讯端口
在计算机中,IPv4的地址用4字节的整数存放,通讯端口用2字节的整数(0-65535)存放。IP地址最高为:255.255.255.255
例如:192.168.190.134 –转化为整数–> 3232284294转化为整数时占用4字节,不转化占用15字节
192 168 190 134
大端:11000000 10101000 10111110 10000110
小段:10000110 10111110 10101000 11000000
四.结构体
sockaddr结构体:
存放协议族、端口和地址信息,客户端和connect()函数以及服务器的bind()函数需要这个结构体
1 | struct sockaddr{ |
sockaddr_in结构体:
sockaddr结构体是为了统一地址结构表示方法,统一接口函数,但是操作不方便所以定义了等价的sockarrd_in的结构体,他的大小与sockaddr相同,可以强制转化成sockaddr
1 | struct sockaddr_in{ |
其中获取32位IP地址大端序获取有如下方案:
以下API在vs2015即被标记为废弃,不建议在新的代码中使用
新版代码位置:
使用gethostbyname函数:
使用域名/主机名/字符串ip获取大端序ip。通常用于客户端
1 | struct hostent *gethostbyname(const char *name); |
转换后将大端序地址代码复制到结构体sockaddr_in中的sin_addr成员中
1 | struct sockaddr_in servaddr; |
使用getaddrinfo代替gethostbyname和gethostbyaddr:
getaddrinfo相比于其他,参数设计非常灵活,支持IPv4/IPv6,多种套接字类型和协议,并且也是线程安全的并且同时也支持跨平台,在Linux中也可以放心替换。
1 |
|
-
hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的十六进制串) -
service:一个服务名称或者10进制端口号数串 -
hints:可以为空指针,也可以为一个指向某addrinfo结构的指针,调用者在这个结构中填入关于期望返回信息的暗示。如果调用者的服务器支持TCP和UDP,那么调用者可以在这个参数的addrinfo中指定成员ai_socktype设置为SOCK_STREAM使得返回的仅仅适用于数据报套接口的信息。 -
result:返回的一个指向addrinfo结构表数据指针,其定义在头文件netdb.h -
addrinfo结构体
1 | struct addrinfo { |
注意:在使用完addrinfo结构体中一定要手动释放
使用freeaddrinfo(res);
完整示例:
1 | // 向服务器发送连接请求 |
五.字符串IP与大端序IP转换
把字符串IP转化为大端序IP,用于网络通讯的服务端中:
c语言提供了几个库函数,用于字符串格式的打IP和大端序IP的相互转化,用于网络通讯服务端程序中。
1 | typedef unsigned int int_addr_t; |
服务端用于通信的IP和端口绑定到socket上
1 | struct sockaddr_in servaddr; |
相较于gethostbyname通过主机名,域名.inet_addr是直接指定IP不支持主机名和域名获取IP。所以多用于服务端,gethostbyname而在客户端使用。
在以上工作完成之后客户端可以连接服务端发送请求
1 | //客户端 |




