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 );
}