字节序:cpu对内存中数据进行存取的顺序
主机字节序的分类:小端、大端
小端:低地址存低位
大端:低地址存高位
#include
using namespace std;
void check_sys1()
{
int a = 1;
char* b = (char*)&a;
if (*b == 1)
cout << "小端" << endl;
if (*b == 0)
cout << "大端" << endl;
}
void check_sys2()
{
//联合类型的所有数据共用一块内存,内存大小根据最大的数据类型决定
union UN {
int a;
char b;
}u;
u.a = 1;
if(u.b==1)
cout << "小端" << endl;
if(u.b==0)
cout << "大端" << endl;
}
int main()
{
check_sys1();
check_sys2();
return 0;
}
主机字节序对网络通信的影响:如果通信两端主机字节序不同,可能会造成数据二义性。
解决方案:订立网络通信字节序标准,规定网络中的数据都按照网络字节序进行存取。网络字节序-----其实是大端字节序。
发送方将数据转换成网络字节序后进行发送,接收方根据自己的的主机字节序将接收到的数据进行转换。
字节序只针对存储单元大于一个字节的数据类型。
注意:字符串实际上是单字节存储,所以不需要转换。
socket 套接字编程:网络通信程序的编写
分类:UDP协议通信程序的/TCP协议通信程序
区别:
UDP协议:用户数据报协议
特点:无连接,不可靠,面向数据报
应用场景:实时性要求大于安全性要求----例如视频传输
TCP协议:传输控制协议
特点:面向连接,可靠,面向字节流
应用场景:安全性要求大于实时性要求----例如文件传输
在网络通信程序中,通信两端被分为客户端和服务端,
客户端:提供给客户的通信段,通常是通信程序中主动发起请求的一端。
客户端必须提前知道服务端的地址信息(ip地址+port端口)才能发送请求,通常是被提前写在应用程序中,并且通常是固定不变的。
netstat命令:查看当前网络状态信息
-a:查看所有
-t :查看TCP信息
-u:查看UDP信息
-n:不宜服务名称显示
-p:查看当前网络状态对应的进程
1、创建套接字:int socket(int domain,int type,int protocol);
domain:地址域类型----指定使用的是什么样的地址结构:AF_INET----IPV4通信,使用IPV4地址结构
type:套接字类型;SOCK_STREAM:流式套接字 / SOCK_DGRAM:数据报套接字注意:TCP协议必须使用SOCK_STREAM,UDP必须使用SOCK_DGRAM
protocol:本次通信所使用的协议;IPPROTO_IP=6 / IPPROTO_UDP=17(可以使用宏,也可以使用数字)
返回值:成功,返回一个文件描述符----操作句柄;失败,返回-1。
2、为套接字绑定地址信息:int bind(int sockfd,struct sockaddr* addr,socklen_t addrlen);
sockfd:socket() 创建套接字返回的操作句柄
addr:当前绑定的地址信息
socklen_t addrlen:地址信息长度
返回值:成功返回0;失败返回-1。
3、接收数据:ssize_t recvfrom(int sockfd,void* buf,int len,int flag,struct addr* srcaddr,socklen_t * addrlen);
ssize_t:有符号int;
size_t:无符号int
sockfd:创建套接字返回的操作句柄
buf:用于存放接收到的数据的空间地址
len:需要接受的数据长度
flag:选项标志,通常默认为0,表示阻塞接收
srcaddr:本条数据的源端地址信息
addrlen:输入输出参数,指定要接收多长的地址长度,但实际可能并没有那么长,所以还会返回实际接收到的地址长度
返回值:成功,返回实际接收到的数据长度;失败或出错返回-1。
4、发送数据:ssize_t sendto(int sockfd,void *data,int len,int flag,struct sockaddr* peeraddr,socklen_t addrlen);
sockfd:操作句柄
data:要发送的数据的首地址
len:要发送的数据长度
flag:默认为0,阻塞发送
peeraddr:对端地址信息
addrlen:地址结构长度
返回值:成功,返回实际发送的数据长度;失败,返回-1。
5、关闭套接字:int close(int fd);
fd:操作句柄
字节序转换接口:
unint32_t htonl(uint32_t hostlong);----32位数据主机字节序到网络字节序的转换
unint16_t htons(uint32_t hostshort);----16位数据主机字节序到网络字节序的转换
unint32_t ntohl(uint32_t netlong);----32位数据网络字节序到主机字节序的转换
unint16_t ntohs(uint32_t netshort);----16位数据网络字节序到主机字节序的转换
注意:port端口转换使用htons/ntohs,ip转换使用htonl/ntohl,不能混用。将字符串点分十进制IP地址转换为整型网络字节序IP地址:
“192.168.2.2”————》0xc0a80202
in_addr_t inet_addr(const char* cp);将网络字节序IP地址转换为字符串点分十进制IP地址:
0xc0a80202————》“192.168.2.2”
char* inet_ntoa(struct in_addr in);以上接口仅限于IPV4地址使用
不限于IPV4的地址转换:
int inet_pton(int af,const char* src,void* dst);
const char* inet_ntop(int af,void* src,char* dst,socklen_t size);
(1)这两个函数的af参数既可以是AF_INET(ipv4)也可以是AF_INET6(ipv6)。如果,以不被支持的地址族作为af参数,这两个函数都返回一个错误,并将errno置为EAFNOSUPPORT.
(2)第一个函数尝试转换由src指针所指向的字符串,并通过dst指针存放二进制结果,若成功则返回值为1,否则如果所指定的af而言输入字符串不是有效的表达式格式,那么返回值为0.
(3)inet_ntop进行相反的转换,从数值格式(src)转换到表达式(dst)。inet_ntop函数的src参数不可以是一个空指针。调用者必须为目标存储单元分配内存并指定其大小,调用成功时,这个指针就是该函数的返回值。size参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。如果size太小,不足以容纳表达式结果,那么返回一个空指针,并置为errno为ENOSPC。