2.1 字节排序问题
考虑一个16位整数,他由2个字节组成。内存中存储这两个字节有两中方法:
一.将低序字节存储在起始地址,这称为小端字节序(网络字节序)。
二.将高序字节存储在起始地址,这称为大端字节序(主机字节序)。
2.2
字节排序函数
h
代表
host, n
代表
network
,
L
代表
long
(
32
位
如
Ipv4
地址),
s
代表
short
(
16
位
如
TCP
或者
UDP
端口号)
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue); // 将主机字节序的端口号转换成套接口地址中的
uint16_t htons(uint16_t host16bitvalue); // 将主机字节序的端口号转换成套接口地址中的
网络字节序端口
uint32_t htonl(uint32_t host32bitvalue); // 同上,转换 Ipv4 地址
uint32_t htonl(uint32_t host32bitvalue); // 同上,转换 Ipv4 地址
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
2.3 字节操纵函数
#include <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
void bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
返回
0
相等,非
0
不相等
bzero
将目标中指定数目的字节置为
0
,常常用来将套接口地址结构初始化为
0
。
bcopy
将指定数目的字节从源移到目标。
bcmp
比较任意两个字节串
#include <string.h>
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes);
void memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
返回
0
相同,非
0
不相同
memset
将目标中指定数目的字节置
c
。
一般选者
bzero
,因为参数比较少。
memcpy
注意该函数的
dest
和
src
位置与
bcopy
不同。
2.4
地址转换函数
该系列函数负责在
ASCII
字符串(人们比较喜欢用的格式:
192.168.0.45
)与网络字节序的二进制值(此值存于套接口地址结构中)间转换地址。
p
代表
ASCII
字符串,
n
代表套接口地址结构中的二进制值
#include <arpa/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr);
返回
1
成功,
0
无效的表达式,
-1
出错
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
返回指向结果的指针成功,
NULL
出错
Family可以是AF_INET,也可以是 AF_INET6。
函数inet_ntop的参数strptr不能是个空指针,调用者必须为目标分配内存并指定大小。成功时此指针即函数的返回值。
2.5 字节流套接口上的read和write函数 :
readn、writen
字节流套接口上的读或写输入或输出的字节数可能比要求的数量少,但这不是错误状况,原因是内核中套接口的缓冲区可能已达到极限。
此时需要调用者再次调用read和write函数,以输入和输出剩余的字节。
这种情况在读字节流套接口时很常见,但在写字节流套接口时只能在套接口非阻塞的情况下才出现。
ssize_t readn(int filedes, void *buff, size_t nbytes);
ssize_t writen(int filedes, const void *buff, size_t nbytes);
ssize_t readn(int fd, void *vptr, size_t n)
{
//不一定能读到n个
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while ( nleft > 0 )
{
if ( ( nread = read ( fd, ptr, nleft ) ) < 0 )
{
if ( errno == EINTR )
{
nread = 0; //中断重启(重读)
}
else
{
return ( -1 );
}
else
{
if ( nread == 0)
{
break; //EOF
字节流结束了
}
}
nleft -= nread;
ptr += nread;
}
return ( n – nleft );
//返回读到的实际字节数目
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while ( nleft > 0 )
{
if ( ( nwritten = write ( fd, ptr, nleft) ) <= 0 )
{
if ( nwritten < 0 && errno == EINTR )
{
nwritten = 0; //中断重启
}
else
{
return ( -1 ); //error
}
}
nleft -= nwritten;
ptr += nwritten;
}
return ( n );
}