目录
UDP编程准备
字节序概述
字节序概念
是指多字节数据的存储顺序,一个字节是不存在存储顺序,并且多字节是一个整体,比如int类型的数据
分类
小端格式:将低位字节数据存储在低地址
大端格式:将高位字节数据存储在低地址
单片机中也存在这种分类,keil调试的时候也会出现这种情况,一般常见的都是小端的模式
注意
LSB:低地址
MSB:高地址
因此小端格式和大端格式取数据的方式不一样,因此不必要担心数据会弄错,在同一台主机中,但是在不同主机就不一定了,因为有些计算机是大端模式,而有些是小端模式,那么就会出现问题了
大-高数低址 小-低数低址
如何判断自己主机上的大小端方式
由于大小端的方式是系统确定好的,人为无法直接改变的
强制类型转换、联合体两种方式判断主机大小端(其实后面还有一种,借助字节序转换函数判断)
大小端重点
1、网络协议指定了通讯字节序—大端
2、只有在多字节数据处理时才需要考虑字节序
3、运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
4、异构计算机之间通讯,需要转换自己的字节序为网络字节序(大端)。在需要字节序转换的时候一般调用特定字节序转换函数
如果忽略了大小端会发生什么?--- 接收的数据会错误
因此为了更好的配合,就规定网络数据传输一定是大端数据
分析好上下三个图就成功了,不管你主机是大端还是小端,只要你使用了相应的函数(这个函数会自动检测主机的大小端模式),(如果发送端主机是小端)那么就会把数据自动转换为大端数据才发送到网络中去,(如果接收端主机是小段)那么网络的大端数据就会被先转换为小端数据再发送给接收端主机
答案为a,画一个内存的图就出来了
大小端所需函数
这四个函数,其中两个函数常用于IP地址传输,另外一个函数常用于端口传输。当然数据的转换也是使用这些函数的
htonl函数
uint32_t htonl(uint32_t hostint32);
功能:
将32位主机字节序数据转换成网络字节序数据--因此使用在发送端主机
一般由于转换IP地址的,把IP地址(32位)发送给接收端主机
参数:
hostint32:待转换的32位主机字节序数据
返回值:
成功:返回网络字节序的值
头文件:
#include <arpa/inet.h>
ntohl函数
uint32_t ntohl(uint32_t netint32);
功能:
将32位网络字节序数据转换成主机字节序数据--因此使用在接收端主机
一般将网络字节序的IP地址转换为主机的IP地址
参数:
uint32_t: unsigned int
netint32:待转换的32位网络字节序数据
返回值:
成功:返回主机字节序的值
头文件:
#include <arpa/inet.h>
记忆方式:host--主机 net--网络 host to net表示主机-网络转换
htons函数
uint16_t htons(uint16_t hostint16);
功能:
将16位主机字节序数据转换成网络字节序数据--因此使用在发送端主机
一般由于将发送端主机端口转换为网络字节序的端口
参数:
uint16_t:unsigned short int
hostint16:待转换的16位主机字节序数据
返回值:
成功:返回网络字节序的值
头文件:
#include <arpa/inet.h>
ntohs函数
uint16_t ntohs(uint16_t netint16);
功能:
将16位网络字节序数据转换成主机字节序数据
一般由于将网络字节序的端口转换为接收端主机的端口
参数:
uint16_t: unsigned short int
netint16:待转换的16位网络字节序数据
返回值:
成功:返回主机字节序的值
头文件:
#include <arpa/inet.h>
因此可以使用字节序函数进行判断你主机是大小端格式
把主机数据转换为网络数据,如果数据不变,说明主机是大端,如果数据变了,那么就是小端存储了
地址转换函数
一般指的就是IP地址
inet_pton函数
int inet_pton(int family,const char *strptr, void *addrptr);
功能:
将点分十进制数串(字符串)转换成32位无符号整数,字符串IP地址转整型数据
使用于发数据
参数:
family 协议族 --- IPV4转换为AF_INET IPV6转换为AF_INET6
strptr 点分十进制数串
addrptr 32位(4字节)无符号整数的地址-因此类型可以为int
返回值:
成功返回1 、 失败返回其它
头文件:
#include <arpa/inet.h>
理解addrptr的意思:四个字节,保存着字符串的数字形式
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
char *ip_str = "192.168.13.100";
unsigned int ip_uint = 0;
unsigned char * ip_p =NULL;//可以用char吗?
inet_pton(AF_INET,ip_str,&ip_uint);
printf("ip_uint = %d\n",ip_uint);
ip_p = (unsigned char *) &ip_uint;
printf("ip_uint = %d.%d.%d.%d\n",*ip_p,*(ip_p+1),*(ip_p+2),*(ip_p+3));
记忆方式:p是point点的意思,to,net
inet_ntop函数
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
功能:
将32位无符号整数转换成点分十进制数串,整型数据转字符串格式ip地址
使用于收数据
参数:
family 协议族
addrptr 32位无符号整数
strptr 点分十进制数串
len strptr缓存区长度
len的宏定义
#define INET_ADDRSTRLEN 16 //for ipv4
#define INET6_ADDRSTRLEN 46 //for ipv6
返回值:
成功:则返回字符串的首地址
失败:返回NULL
头文件:
#include <arpa/inet.h>
对于IPV4是十六字节,对于字符串"198.162.100.100",就是16个字节
#include<stdio.h>
#include<arpa/inet.h>
int main()
{
unsigned char ip[]={192,168,13,252};
char ip_str[16];
inet_ntop(AF_INET,(unsigned int *)ip,ip_str,16);
printf("ip_str = %s\n",ip_str);
return 0;
因此对于一个IP地址的转换,你就涉及到了把字符串IP地址转换为32为数字,然后再使用字节序函数转换为大端数据才能传输