读书笔记之《UNIX网络编程 第一卷》第三章

本文介绍了UNIX环境下套接口编程的基础知识,包括套接口地址结构、字节序转换、字符串与网络字节序转换函数等内容。重点讲解了IPv4与IPv6下的套接口地址结构以及相关的套接口函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《UNIX 网络编程 第一卷》


第三章 套接口编程简介


3.1 概述


协议有关函数
地址转换函数: ipv4  inet_addr()、inet_ntoa().
 ipv6 inet_pton()、inet_ntop().
协议无关函数:以 “sock_” 为前缀。


3.2 套接口地址结构

套接口地址结构以 “sockaddr_协议族名” 命名


IPv4 struct sockaddr_in <netinet/in.h>

struct in_addr {
in_addr_t s_addr; /* 32-bit IPv4 address network byte ordered */
}


struct sockaddr_in {
uint8_t sin_len; /* 1 length of structure (16) */
sa_family_t sin_family; /* 1 AF_INET family = AF_INET | AF_INET6 */
in_port_t sin_port; /* 2 16-bit TCP or UDP port number netword byte ordered */
struct in_addr sin_addr; /* 4 32-bit IPv4 address network byte ordered */
char sin_zero[8]; /* 8 unused */
}


从进程到内核传递套接口地址结构的套接口函数:bind、connect、sendto、sendmsg.
从内核到进程传递套接口地址结构的套接口函数:accept、recvfrom、recvmsg、getpeername、getsockname.


数据类型 头文件 说明
int8_t <sys/types.h> 带符号的8位整数
uint8_t <sys/types.h> 无符号的8位整数
int16_t <sys/types.h> 带符号的16位整数
uint16_t         <sys/types.h> 无符号的16位整数
int32_t <sys/types.h> 带符号的32位整数
uint32_t         <sys/types.h> 无符号的32位整数
sa_family_t <sys/socker.h> 套接口地址结构的地址族
socklen_t <sys/socker.h> 套接口地址结构的长度,一般位uint32_t
in_addr_t <netinet/in.h> IPv4地址,一般为uint32_t
in_port_t <netinet/in.h> TCP或UDP端口,一般为uint16_t

通用套接口地址结构 struct sockaddr <sys/socket.h>

struct sockaddr {
uint8_t sa_len; /* 1 length of structure (16) */
sa_family_t sa_family; /* 1 address family; AF_xxx value */
char sa_data[14]; /* 14 protocol-specific address */
}


套接口函数被定义为采用只想通用套接口地址结构的指针:如 int bind(int, struct sockaddr *, socklen_t)。
对这些函数的调用必须指向某协议的套接口地址的指针类型转成指向通用套接口地址结构的指针:如 
struct sockaddr_in serv; /* IPv4 socket address structure */
bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));


IPv6 struct sockaddr_in6 <netinet/in.h>

struct in6_addr {
uint8_t s6_addr[16]; /* 16 128-bit IPv6 address network byte ordered */
};

#define SIN6_LEN /* required for complile_time test */
struct sockaddr_in6 {
uint8_t sin6_len; /* 1 length of this struct(24) */
sa_family_t sin6_family; /* 1 AF_INET6 */
in_port_t sin6_port; /* 2 transport layer port network byte ordered */
uint32_t         sin6_flowinfo; /* 4 priority & flow label network byte ordered */
struct in6_addr sin6_addr; /* 16 IPv6 address network byte ordered */
}

sin6_flowinfo 成员分成三个字段: 1.低24bit是流量标号; 2.下4bit是优先级; 3.再下4bit保留.


四种套接口地址结构:
sockaddr_in{} (IPv4 16B)、sockaddr_in6{} (IPv6 24B)、sockaddr_un{} (Unix 变长104B)、sockaddr_dl{} (Datalink 变长)

3.3 值-结果参数


从进程到内核传递套接口地址结构函数:bind、connect、sendto,其中两参数 1.套接口地址结构指针; 2.结构的大小整数值. 如:
struct sockaddr_in serv;
connect(sockfd, (struct sockaddr *) &serv, sizeof(serv)); 内核拷贝数据长度是知道的。
从内核到进程传递套接口地址结构函数:accept、recvfrom、getsockname、getpeername,其中两参数 1.套接口地址结构指针; 2.结构的大小整数值的指针. 如:
struct sockaddr_un cli;
socklen_t len;
len = sizeof(cli);
getpeername(unixfd, (struct sockaddr *)&cli, &len);
这种方式叫做:值-结构参数。


3.4 字节排序函数


大、小端字节序:大端、小端表示多字节值的哪一端(大端或小段)存储在该值的起始地址(通常起始地址为低位地址)
小端字节序(BIG-ENDIAN):“高高低低”,代表语言:C/C++
大端字节序(LITTLE-ENDIAN):“高低高低”,代表语言:Java/网络字节序

转换函数:<netinet/in.h>
host to network short/long network to host short/long
uint16_t htons(uint16_t host16bitvalue); uint16_t ntohs(uint16_t net16bitvalue);
uint32_t htonl(uint32_t host32bitvalue); uint32_t ntohl(uint32_t net32bitvalue);

3.5 字节操纵函数
"str"开头函数,C字符串处理函数,以'\0'为结束符:strcat、strcmp...
"b"开头函数,C字节处理函数: <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
int     bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
"mem"开头函数,C内存处理函数: <string.h>
void   *memset(void *dest, int c, size_t len);
void   *mencpy(void *dest, const void *src);
int      memcmp(const void *ptr1, const void *ptr2, size_t nbytes);




3.6 ASCII字符串与网络字节序转换函数

inet_aton、inet_addr、inet_ntoa 点分十进制数串与32位网络字节序二进制值间转换IPv4地址
inet_pton、inet_ntop 对IPv4和IPv6地址都能进行处理(presentation 地址表达格式="ASCII", numeric 数值表达格式="二进制") 
把函数参数考虑其中,上面这些函数都是协议相关函数.
sock_ntop <unp.h>自定义函数,根据套接字接口指针查看协议类型,然后再调用适当函数(具有协议无关性).

#include <arpa/inet.h>
int         inet_aton(const char *strptr, struct in_addr *addrptr);  返回值:1 串有效、0串无效。
in_addr_t inet_addr(const chat *strptr); 返回:INADDR_NONE表示串无效,INADDR_NONE = inet_addr("255.255.255.255")。
char* inet_ntoa(struct in_addr inaddr); 返回:指向点分十进制数串的指针。


#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 否则 返回结果错误并置errno为EAFNOSUPPORT.
len是目标地址的大小,以免函数溢出其调用者的缓冲区. 其值定义在<netinet/in.h>为:
#define INET_ADDRSTRLEN 16 /* for IPv4 dotted-decimal */
#define INET6_ADDRSTRLEN 46  /* for IPv6 hex string */

#include "unp.h"
char* sock_ntop(const struct sockaddr *sockaddr, socklen_t, socklen_t addrlen); 返回值: 非空指针——成功, NULL——出错
表达式格式:IPv4(xxx.xxx.xxx.xxx)或IPv6(xxxx:xxxx:xxxx:xxxx:xxxx:xxxx.portId'\0'), addrlen = 22|52
int sock_bind_wild(int sockfd, int family); 返回:0 成功, -1 出错
int         sock_cmp_addr(const struct sockaddr *sockaddr1, const struct sockaddr *sockaddr2, socklen_t addrlen); 返回:0相等,非0不等
int sock_cmp_port(const struct sockaddr *sockaddr1, const struct sockaddr *sockaddr2, socklen_t addrlen); 返回:0相等,非0不等
int sock_get_port(const struct sockaddr *sockaddr, socklen_t addrlen); 返回:unsigned int 端口号,否则-1
char* sock_ntop_host(const struct sockaddr *sockaddr, socklen_t addrlen); 返回:非空指针——成功, NULL——出错
void         sock_set_addr(const struct sockaddr *sockaddr, socklen_t addrlen, void *ptr);
void         sock_set_port(const struct sockaddr *sockaddr, socklen_t addrlen, int port);
void        sock_set_wild(struct sockaddr *sockaddr, socklen_t addrlen);


3.7 字节流套接口读写函数


read、write #include <unistd.h> /* 在读写套接字接口时,返回数据很可能比要求的少,并没出错 */
readn、writen、readline #include "unp.h" /* 解决了read、write读写数据比要求的少这个问题 */

ssize_t readn (int filedes, void *buff, size_t nbytes); 从一个描述字读n bytes
ssize_t writen(int filedes, const void *buff, size_t nbyptes); 写入一个描述字n bytes
ssize_t readline(int filedes, void *buff, size_t maxlen); 从一个描述字读文本行,one time one byte
/* 均返回:读写字节数, -1——出错 */


3.8 isfdtype函数

功能:用来测试一个描述字是否是某给定类型。
isfdtype #include <sys/stat.h>

int isfdtype(int fd, int fdtype); 返回:1——是指定类型, 0——不是指定类型, -1——出错
当测试是否为套接口描述字,fdtype应设成S_IFSOCK.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值