C/C++Unix网络编程-套接字编程简介

套接字地址结构

套接字的地址结构可以在两个方向上传播:从进程到内核和从内核到进程。

IPV4套接字地址结构

在这里插入图片描述

  • sin_len是长度字段,有的平台上的套接字没有这个东西,因为有外置的sizeof运算符。不是posxi标准强制的字段
  • sin_family,sin_addr,sin_port是posxi标准规定必须有的字段,分别是协议簇,IP地址,端口号。
  • sin_zero可以理解为占位符吧,供以后使用。而且也以便统一大小,所有的套接字地址结构大小都至少是16字节

在这里插入图片描述
注:sa_family_t一般是8位无符号整数,也可以是16位无符号整数。

定义数据类型是为了统一不同主机的类型,比如x86和x64,两台机器之间网络通信,那么不能用什么int和double这样的东西,因为这个东西在不同的机器上占用的空间可能是不一样的,而上述这些类型,确保在所有机器上都是一样的。套接字地址结构仅在给定主机上使用:虽然结构中的某些字段用在不同主机之间的通信中,但是结构本身并不在主机之间传递。

IPv 4地址和tcp或udp端口号在套接字地址结构中总是以网络字节序来存储。

通用的套接字地址结构

在这里插入图片描述
一般各种函数的参数都是通用套接字地址结构,而主机上使用的是固定的套接字地址结构,比如上面说的IPV4的套接字地质结构struct sockaddr_in,在C语言里可以用void*进行类型转换,但是在C++里不可以。比如:
在这里插入图片描述

IPV6的套接字地址结构

在这里插入图片描述

  • IPV6的协议簇是AF_INET6,IPV4是AF_INET

新的通用套接字地址结构

在<netinet/in.h>中定义
在这里插入图片描述
学unix环境高级编程的时候,没见用过这个结构体。

不同套接字的地址结构的比较

在这里插入图片描述

值-结果参数

我们提到过,当往一个套接字函数传递一个套接字地址结构时,该结构总是以引用形式来传递,也就是说传递的是指向该结构的一个指针。该结构的长度也作为一个参数来传递,不过其传递方式取决于该结构的传递方向:是从进程到内核,还是从内核到进程。

(1)从进程到内核传递套接字地址结构的函数又3个:bind、connect、sendto;这些函数的一个参数是套接字地址结构体的指针,另一个参数是结构体的整数大小;代表入参:
在这里插入图片描述
传递地址和大小的原因是告诉内核,应该复制那快内存,复制多大的内存。
在这里插入图片描述
(2)从内核到进程传递套接字地址结构体的函数有4个:accept、recvfrom、getsockname、getpeername;结构体指针和结构体大小的指针,都代表出参。
在这里插入图片描述

字节排序函数

字节序:大小端:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址.
在这里插入图片描述
这两种字节序没有标准,且都有系统实用,而且还允许一个系统两者切换,所以我们把某个给定系统所用的字节序成为主机字节序;但是网络协议需要网络字节序
举例来说,在每个TCP分节中都有16位的端口号和32位的IPv4地址。发送协议栈和接收协议栈必须就这些多字节字段各个字节的传送顺序达成一致。网际协议使用大端字节序来传送这些多字节整数。

主机字节序与网络字节序相互转换

在这里插入图片描述

字节操纵函数

操纵多字节字段的函数有两组,它们既不对数据作解释,也不假设数据是以空字符结束的C字符串。当处理套接字地址结构时,我们需要这些类型的函数,因为我们需要操纵诸如IP地址这样的字段,这些字段可能包含值为0的字节,却并不是C字符串。以空字符结尾的C字符串是由在<string.h>头文件中定义、名字以str(表示字符串)开头的函数处理的。

BSD标准:现今几乎所有的套接字函数都只有它们,因为参数比较少,所以比较好记:
在这里插入图片描述
ANSI C标准:C标准库函数:
在这里插入图片描述
memset把目标字节串指定数目的字节置为值c。memcpy类似bcopy,不过两个指针参数的顺序是相反的。当源字节串与目标字节串重叠时,bcopy能够正确处理,但是memcpy的操作结果却不可知。这种情形下必须改用ANSI C的memmove函数。
memcmp比较两个任意的字节串,若相同则返回0,否则返回一个非0值,是大于0还是小于0则取决于第一个不等的字节:如果ptr1所指字节串中的这个字节大于ptr2所指字节中的对应字节,那么大于0,否则小于0。我们的比较操作是在假设两个不等的字节均为无符号字符( unsigned char)的前提下完成的。

inet_aton、inet_addr、inet_ntoa函数

地址转换函数,它们在ASCII字符串(这是人们偏爱使用的格式)与网络字节序的二进制值(这是存放在套接字地址结构中的值)之间转换网际地址。
在这里插入图片描述
第一个函数inet_aton将strptr所指C字符串转换成一个32位的网络字节序二进制值,并通过指针addrptr来存储。若成功则返回1,否则返回0。

inet_addr已经被弃用。
inet_addr进行相同的转换,返回值为32位的网络字节序二进制值。该函数存在一个问题:所有22个可能的二进制值都是有效的IP地址(从0.0.0.0到255.255.255.255),但是当出错时该函数返回INADDR_NONE常值(通常是一个32位均为1的值)。这意味着点分十进制数串255.255.255.255(这是IPv4的有限广播地址,见20.2节)不能由该函数处理,因为它的二进制值被用来标识该函数失败。
inet_addr函数还存在一个潜在的问题:一些手册页面声明该函数出错时返回-1而不是工NADDR_NONE。这样在对该函数的返回值(一个无符号的值)和一个负常值(-1)进行比较时可能会发生问题,具体取决于C编译器。

inet_ntoa函数将一个32位的网络字节序二进制IPv4地址转换成相应的点分十进制数串。由该函数的返回值所指向的字符串驻留在静态内存中。这意味着该函数是不可重入的,这个概念我们将在11.18节中讨论。最后需要留意,该函数以一个结构而不是以指向该结构的一个指针作为其参数。
函数以结构为参数是罕见的,更常见的是以指向结构的指针为参数。

inet_pton、inet_ntop函数

ipv4和ipv6都适用,进行大整数与点分式之间的转换。
函数名中p和n分别代表表达(presentation)和数值(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构中的二进制值。
在这里插入图片描述
len参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。为有助于指定这个大小,在<netinet/in.h>头文件中有如下定义:
在这里插入图片描述
在这里插入图片描述

sock_ntop和相关函数

inet_ntop的一个基本问题是:它要求调用者传递一个指向某个二进制地址的指针,而该地址通常包含在一个套接字地址结构中,这就要求调用者必须知道这个结构的格式和地址族。
在这里插入图片描述
而sock_ntop就是把这两个合并,不用再区分IPV4和IPV6,不是标准函数。
这也是这本书比较恶心的地方,tmd教人还用自己写的接口,还不放出接口源代码。

readn、writen、readline函数

字节流套接字(例如TCP套接字)上的read和write函数所表现的行为不同于通常的文件IO。字节流套接字上调用read或write输入或输出的字节数可能比请求的数量少,然而这不是出错的状态。这个现象的原因在于内核中用于套接字的缓冲区可能已达到了极限。此时所需的是调用者再次调用read或write函数,以输入或输出剩余的字节。有些版本的Unix在往一个管道中写多于4096字节的数据时也会表现出这样的行为。这个现象在读一个字节流套接字时很常见,但是在写一个字节流套接字时只能在该套接字为非阻塞的前提下才出现。尽管如此,为预防万一,不让实现返回一个不足的字节计数值,我们总是改为调用writen函数来取代write函数。
在这里插入图片描述
注:readn和writen这两个函数是我们自己定义的,只是为了以后方便使用。它们并非任何标准的组成部分。
还是建议实用标准的io函数,read,write。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙子砰砰枪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值