字节序
(1)字节系相关概念
字节序:是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:即大端格式、小端格式。小端格式(Little-Endian):将低位字节数据存储在低地址。大端格式(Big-Endian):将高位字节数据存储在低地址。
为何使
(1)计算机电路先处理低位字节,效率比较高。因为计算就是从低位开始的,所以计算机内部很多都是小端字节序。
(2)格式规范是为人类编写的,大端字节序更符合人类习惯。
网络字节序通常是大端字节序(Big Endian)。在网络通信中,数据通常以大端字节序进行传输,这是为了确保不同系统之间能够正确解释数据。因此,在网络编程中,我们通常会使用函数如 htons() 和 htonl() 来将主机字节序转换为网络字节序(大端字节序),以便在网络中正确传输数据。
2)有关字节序转换的函数
以下所有接口的头文件都是: #include <arpa/inet.h>
①主机字节序转换网络字节序函数函数原型:
uint16_t htons(uint16_t hostshort);//将16位主机字节序数据转换成网络字节序数据 uint32_t htonl(uint32_t hostlong);//将32位主机字节序数据转换成网络字节序数据
①主机字节序转换网络字节序函数
函数原型:
uint16_t htons(uint16_t hostshort);//将16位主机字节序数据转换成网络字节序数据 uint32_t htonl(uint32_t hostlong);//将32位主机字节序数据转换成网络字节序数据
函数功能:htons将16位主机字节序数据转换成网络字节序数据 htonl将32位主机字节序数据转换成网络字节序数据 参数说明: hostshort:需要转换的16位主机字节序数据,uint16_t:unsigned short int hostlong:需要转换的32位主机字节序数据,uint32_t:32位无符号整型 返回值: 成功返回网络字节序的值。
inet_addr() 是一个函数,用于将点分十进制表示的IPv4地址转换为网络使用的二进制格式。
inet_intoa 是一个在编程中使用的函数,用于将IPv4地址从其二进制表示转换为人类可读的字符串格式。它接受一个表示IPv4地址的整数值,并返回一个格式为"x.x.x.x"的字符串,其中每个"x"表示0到255之间的数字。这个函数通常用于网络编程中,以更易读的格式显示IP地址。
inet_aton是一个函数,用于将一个IPv4地址的点分十进制表示法(例如:"192.168.1.1")转换为其32位的二进制表示形式。这个函数通常在网络编程中使用,以便将人类可读的IP地址转换为计算机可理解的形式,以便进行网络通信和数据处理。
下面两个是经常使用的,因为包括ipv4和ipv6:
inet_pton 是一个函数,用于将IPv4或IPv6地址从其人类可读的字符串表示形式转换为网络字节序的二进制表示形式。它接受一个表示IP地址的字符串和地址族(AF_INET或AF_INET6),并将其转换为适当的二进制形式。这个函数通常在网络编程中使用,以便将IP地址转换为适合网络通信的形式
inet_ntop 是一个函数,用于将网络字节序的IPv4或IPv6地址转换为其人类可读的字符串表示形式。它接受一个指向包含IP地址的结构体的指针,以及地址族(AF_INET或AF_INET6),并返回一个指向包含转换后IP地址的字符串的指针。这个函数通常在网络编程中使用,以便将二进制形式的IP地址转换为人类可读的形式,以便进行输出或显示。
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. <span data-type="em">/</span> <span data-type="em">struct in_addr sin_addr; /</span> Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
socket套接字相关函数
1.socket 编程流程
(1)TCP通信流程服务器
1.创建套接字(socket)
2.将socket与IP地址和端口绑定(bind)
3.监听被绑定的端口(listen)
4.接收连接请求(accept)
5.从socket中读取客户端发送来的信息(read)
6.向socket中写入信息(write)
7.关闭socket(close)
客户端
1.创建套接字(socket)
2.连接指定计算机的端口(connect)
3.向socket中写入信息(write)
4.从socket中读取服务端发送过来的消息(read)
5.关闭socket(close)
1.使用函数socket(),生成套接字文件描述符;
2.通过struct sockaddr_in 结构设置服务器地址和监听端口;
3.使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;
4.接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;
5.向客户端发送数据,使用sendto() 函数向服务器主机发送数据;
6.关闭套接字,使用close() 函数释放资源;
客户端:
1.使用socket(),生成套接字文件描述符;
2.通过struct sockaddr_in 结构设置服务器地址和监听端口;
3.向服务器发送数据,sendto() ;
4.接收服务器的数据,recvfrom() ;
5.关闭套接字,close() ;
2.socket 相关函数
(1)socket()函数(创建套建字)
函数原型
int socket(int domain, int type, int protocol);
- 参数:
domain:指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族); - 国内一般使用ipv4AF_INET IPv4因特网域
AF_INET6 IPv6因特网域
AF_UNIX Unix域
AF_ROUTE 路由套接字
AF_KEY 密钥套接字
AF_UNSPEC 未指定
type:参数指定socket的类型:
SOCK_STREAM: 流式套接字提供可靠的,面向连接的通信流,它使用TCP协议,从而保证了数据传输的正确性和顺序性
SOCK_DGRAM: 数据报套接字定义了一种无连接的服,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠,无差错的。它使用数据报协议UDP
SOCK_RAW:
允许程序使用底层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。
protocol:通常赋值为“0”
0选择type类型对应的默认协议
IPPROTO_TCP TCP传输协议
IPPROTO_UDP UDP传输协议
IPPROTO_SCTP SCTP传输协议
IPPROTO_TIPC TIPC传输协议
返回值:成功返回非负套接字描述符,失败返回-1
————————————————
(2)bind()函数(绑定套建字)
函数原型:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数说明: 用于绑定IP地址和端口号到socket
参数:sockfd:是一个socket描述符 addr:是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数说明: 用于绑定IP地址和端口号到socket
参数:sockfd:是一个socket描述符 addr:是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。
上述两者结构体长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。 一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。
addrlen:地址的长度,一般用sizeof(struct sockaddr_in)表示
返回值:成功返回0,失败返回-1
(3)listen()函数(监听被绑定的端口)
函数原型:
int listen(int sockfd, int backlog);
函数说明:
功能:
设置能处理的最大连接数,listen并未开始接受连线,只是设置了socket的listen模式,listen函数只用于服务器端,服务器进程不知道要与谁进行连接,因此,它不会主动的要求与某个进程连接,只是一直监听是否有其他客户进程与之连接,然后响应该连接请求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接,主要就连个功能:将一个未连接的套接字转换为一个被动套接字(监听),规定内核为相应套接字排队的最大连接数。
内核为任何一个给定监听套接字维护两个队列:
未完成连接队列,每个这样的SYN报文段对应其中一项:已由某个客户端发出并到达服务器,而服务器正在等待完成相应的TCP三次握手过程,这些套接字处于SYN_REVD状态
已完成连接队列,每个已完成TCP三次握手过程的客户端对应其中一项,这些套接字处于ESTABLISHED状态;
参数:
sockfd:socket系统调用返回的服务端socket描述符
backlog:指定在请求队列中允许的最大的请求数,大多数系统默认为5
返回值:成功返回0,失败返回-1
(4)accept()函数(接收连接请求)
函数原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数说明:
accept函数由TCP服务器调用,用于从已完成连接队列对头返回下一个已完成连接,如果已完成连接队列为空,那么进程被投入睡眠。
参数:
sockfd:是socket系统调用返回的服务器端socket描述符
addr:用来返回已连接的对端(客户端)的协议地址
addrlen:客户端地址长度,注意需要取地址
返回值:
该函数的返回值是一个新的套接字的描述符,返回值是表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述符,一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接字(表示TCP三次握手已完成),当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。
accept正确返回就表示我们已经和前来连接我的客户端之间建立了一个TCP连接了, 以后我们就要通过这个连接来和客户端进行读写操作, 读写操作就需要一个fd,这个fd就由accept来返回了。
(5)connect()函数(发送连接请求)
- 函数原型:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数说明: 该函数用于绑定之后的client端(客户端),与服务器建立连接
参数:
sockfd:创建的socket描述符
addr:服务端的ip地址和端口号的地址结构指针
addrlen:地址的长度,通常被设置为sizeof(struct sockaddr)
返回值:成功返回0,遇到错误时返回-1,并且errno中包含相应的错误码
(6)send()、recv()(TCP发送、接收信息)
- send函数原型:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
函数说明: 函数只能对处于连接状态的套接字进行使用,参数sockfd为已建立好连接的套接字描述符
参数:sockfd:为已建立好连接的套接字描述符即accept函数的返回值buf:要发送的内容len:发送内容的长度flags:设置为MSG_DONTWAITMSG 时 表示非阻塞,设置为0时 功能和write一样
返回值:成功返回实际发送的字节数,失败:返回 -1
————————————————
- recv函数原型:
ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
函数说明:接收套接字中的数据
参数:
sockfd:在哪个套接字接
buf:存放要接收的数据的首地址
len:要接收的数据的字节
flags:设置为MSG_DONTWAITMSG 时 表示非阻塞,设置为0时 功能和read一样
返回值:成功返回实际发送的字节数,失败:返回 -1
————————————————
(7)sendto()、recvfrom()函数(UDP发送、接收消息)
- 函数说明:UDP发送消息
-
- sendto()函数原型:
- int sendto(int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
参数说明:
s: socket描述符;
buf:UDP数据报缓存区(包含待发送数据);
len: UDP数据报的长度;
flags:调用方式标志位(一般设置为0),设置为MSG_DONTWAITMSG 时 表示非阻塞
to: 指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);之前介绍bind函数时已经介绍。
tolen:to所指结构体的长度;
返回值:成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。
————————————————
- recvfrom()函数原型:
int recvfrom(int s, void *buf, int len, unsigned int flags,struct sockaddr *from, int *fromlen);
函数说明:UDP接收消息
参数:
s: socket描述符;
buf: UDP数据报缓存区(包含所接收的数据);
len: 缓冲区长度。
flags: 调用操作方式(一般设置为0),设置为MSG_DONTWAITMSG 时 表示非阻塞
from: 指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);
fromlen:指针,指向from结构体长度值。
返回值:成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。
————————————————