5.Linux网络编程基础API

这一章可能和之前TCP/IP网络编程有部分重合,就当复习巩固了,并且取长补短。

1、主机字节序和网络字节序
这个问题怎么产生呢。我们知道现在的32位机器的CPU累加器一次至少装载4个字节,也就是一个int类型。那么这4个字节的在内存中的排列顺序将影响他被累加器装载成的值。这就是字节序问题。
字节序又被分为大端和小端两种。大端指的是数据的高位字节存储在内存的低地址中,小端反过来。而在PC机中,大多采用小端字节序(主机字节序)。所以我们就知道了我们平时取地址&a,取的是内存的最低地址的那个字节,里面存的是a最低位的字节,但是取出来的是整个a。
如果两台机器存储方式不一样,那么必然数据会产生错误。如何解决呢?
那就需要格式化输出,采用网络字节序在网络中传输。输出到网络时,必须转换成大端字节序。这时候目标机就可以根据自身的存储方式判断接收数据时是否转换字节序。
需要注意的是,即使在一台主机,不同的进程的之间也有可能字节序不一样。比如JAVA虚拟机采用的就是大端字节序,C编写的就是小端字节序。
那么,LINUX提供了一下四种函数来完成转换字节序:
在这里插入图片描述
其中h代表主机,n代表网络,l,s分别代表long,int.函数名言简意赅。比如第一个就是32位的主机字节序转换成32位的网络字节序。长整型32位通常用来转换IP地址,短整型用来转换端口号。当然不限于此,这只是最主要的作用。

2、通用socket地址
在这里插入图片描述
socket地址通常用sockaddr结构体来表示。
sa_family是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。地址族有AF_UNIX,AF_INET,AF_INET6,对应着,unix,TCP/IPV4,TCP/IPV6协议族,其中最常见的就是TCP/IPV4。

sa_data存放着socket地址值。但是不同协议族地址值有不同的含义和长度,比如unix地址值代表着文件路径名,最长达108字节。而最常用的就是TCP/IPV4协议族,地址名包含16位的端口号和32位的ipv4地址,共6个字节。

在这里插入图片描述
3.专用socket地址
显然,上面两种通用的地址都不好使用,长度不一致。所以linux为每种协议族定制了特制的地址。我们主要学习tcp/ipv4协议族的。
在这里插入图片描述
4、ip地址转换函数
我们通常见到的192.2.3.3都是点分十进制的表示,方便别人理解。但是计算机只能理解二进制的数字。所以编程时需要转换成二进制,而在记录日志或者输出时需要转换成点分十进制。下面三个函数就是完成互相转换的
在这里插入图片描述

inet_add从返回值和参数可以看出,是将由字符串表示的点分十进制转换成网络字节序的32位整数形式的ipv4地址。
inet_aton和第一个是一样的功能,但是他把结果存储到inp指向的地址结构中,成功返回1,失败返回0,所以返回值是int类型。
inet_ntoa是把32位网络字节序的ipv4地址转换成点分十进制的,不过要注意返回值是一个指针,指针指向的内存是转换的结果。因此该函数不可重入的,啥意思呢:
在这里插入图片描述
这说明指针指向的内存是静态分配的,不会变的,第二次会覆盖第一次的结果。

接下来要说的就是如何创建,分配,监听,连接socket。
1、创建socket;
在linux中所有都是文件,socket也是一个可读可写可关闭的文件描述符。
在这里插入图片描述
domain代表所用的协议族,比如PF_INET,PF_UNIX等。
type指的是服务类型,主要有流服务(SOCK_STREAM)和数据报服务(SOCK_UGRAM)。而在TCP/IP协议族中,流服务就是TCP协议,数据报服务就是用UDP协议。
第三个参数就是在第二种服务类型中制定一个具体的服务。而我们基本都用TCP/IP,所以就只有一种,所以第三个参数基本都设置为0;
成功时返回一个文件描述符(int),失败时返回-1;

2.命名socket;
在这里插入图片描述
用于给一个socket分配一个具体的socket地址。服务器端必须要分配地址,客户端才知道怎么连接。客户端不用分配,操作系统会自动分配。
看具体参数,bind将my_addr具体socket地址分配给sockfd代表的文件描述符,第三个参数是该地址的长度。

3、监听socket
在这里插入图片描述
服务器端必须经过Listen函数创建一个监听队列,才能受理客户端的连接。backlog是队列长度。完整连接数通常为backlog+1.
我们再学习一下如何使用telnet建立连接和netstat查看连接状态。以及网络常用的命令:
1、ping命令:我们常常用来判断2台或2台以上的机器间是否网络连通。
ping /?就可以查看Ping各种参数的具体用法。
2、ipconfig命令:往往是用来查看我们计算机的IP、网关、子网掩码、DNS等信息 ipconfig -all
3、netstat命令:查看本地计算机的端口是否监听netstat -a
4.telnet命令: telnet提供对远程机器的终端服务,即本地机器作为远程的一个虚拟终端对远程机器进行操作。 检查远程机器或本地机器上某端口是否打开

4、接受连接
在这里插入图片描述
这个函数需要注意的是:
函数会返回一个新的socket文件描述符,这个唯一标识了被接受的这个连接,与客户端通信读写就是通过这个新的连接socket文件描述符。
并且,accept对连接的状态,网络的变化不关心,只是从监听队列中取出一个受理。比如当队列中某个连接客户端掉线了,accept仍然会取出该连接受理。

下面是对于客户端:
1.发起连接:在这里插入图片描述
连接成功的话,客户端就是通过返回的sockfd来与服务器进行通信。

2、关闭连接:
在这里插入图片描述
调用close后并不是立即关闭一个连接,而是fd的引用数-1,只有当fd引用计数为0时,才真正关闭。所以,当我们fork一个子进程,fd就会加一,所以,必须在子进程和父进程同时使用close()函数,才可以真正关闭和这个连接。

在这里插入图片描述
showdown不但可以真正关闭,而且可以通过howto实现“优雅地半关闭”
在这里插入图片描述

5.8 TCP数据读写
在这里插入图片描述buf和len通常为缓冲区位置和大小。flag一般设为0,提供额外的控制,先不说了。
要注意的是,recv成功时返回读取数据的长度,他可能小于期望的长度len,因此需要多次调用recv函数。recv返回0表示对方已经关闭连接了。
send表示往socketfd上写数据,成功时返回的是写的长度是len。

对UDP也有类似的函数,还有一种通用的对TCP和UDP都适用的读写函数。这里就不介绍了。
那么,为什么recv会小于期望长度呢?这就需要我们了解TCP,UDP的区别之处。
TCP数据收发无边界。怎么理解呢?我么可以看成是两个工人通过传送带传输糖果,糖果不会丢失,但是发出者发出100个糖果,可能是分批传送的,接受者可能凑齐100个才装袋。收发数据时存在缓冲区,接受者可能调用一次read全部读取,也可能多次读取,所以小于len了。所以基于TCP的套接字不存在数据边界。

5.9带外标记
在这里插入图片描述
5.10地址信息函数
有时候我们想要知道一个连接socket的本端socket地址和远端socket地址。
本端指的就是服务器端,远端是被连接的那个客户端。
在这里插入图片描述
socket选项:

在这里插入图片描述
这两个函数是用来读取和设置socket文件描述符属性的方法;socket有很多重要选项比如设置缓冲区大小,等待时间等,具体的就不想详细说了,我们只要知道有这两个函数可以设置和查看这些属性就行了。

5.12 网络信息API
我们知道socket两个要素是IP地址和端口号,都是用数值表示的,这不方便记忆。我们可以用主机名代替IP地址,服务名代替端口号。比如telent客户端程序就是通过一些网络信息API完成转换的。
telent 127.0.0.1 80=telent localhost www

gethostbyname通过主机名获取主机完整信息
gethostbyaddr通过IP地址获取主机完整信息
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值