Linux网络编程基础
本文由作者单独整理归纳,实属不易,难免存在漏、错地方,如有发现,请留言指出,定将及时纠正。
1. OSI模型
网络体系结构指的是网络的分层结构、以及每层使用的协议的集合。(公司很多部门,每个部门有不同的工作范畴) OSI协议参考模型是典型的网络体系结构,主要分一下七层:
OSI参考模型
应用层——————<高层>:应用于不同的软件
表示层——————<高层>:数据格式转换
会话层——————<高层>:找到传输层并调用,进行传输
传输层——————<低层>:数据打包并发送
网络层——————<低层>:寻找发送路线
数据链路层————<低层>:参数差错处理、屏蔽硬件差异
物理层——————<低层>:解决不同硬件间的通信
本文并不讲全所有的层,只摘取重点
作用:
1.物理层:
负责通过光纤等介质将两台计算机连起来,然后在计算机之间通过高低电频传送0/1这样的电信号
2.数据链路层:
0/1毫无规则的话计算机看不懂,制定个0/1传送规则,多少电信号为一组,每组怎么标识,以太网协议出现
以太网协议规定:一组电信号构成一个数据包,称为帧,由标头和数据两部分构成,大小一般为64 ——1518字节。
帧的长度不固定,标头长度固定,18字节,每帧单独发送,数据部分则是具体数据,接受者需要接受的内容
3.MAC地址:
把A的数据通过物理层和数据链路层发给另外的谁呢?怎么区分电脑与电脑呢?
每个进入网络的计算机都有网卡接口,每个网卡都有一个唯一的地址,这个地址叫MAC地址。
计算机之间的数据传送,就是通过MAC地址来唯一寻找、传送的。MAC地址由48字节构成,网卡生产时被唯一标识了
计算机A通过ARP协议得到计算机B的MAC地址,通过的是广播方式,信息携带的IP与自身比较,匹配则反馈,否则忽略
4.网络层:
首先我们要清楚我们所处的网络由无数个子网构成,网络就像学校,希望就像班级。
在广播的时候,也只有同一个子网的计算机可以收到你的信息,那么,怎么确定是否在同一子网呢?
-
区分MAC地址属不属于同一子网的办法: IP协议
问题来了:IP协议怎么区分MAC地址的?
IP协议所定义的地址称为IP地址,IP协议分IPV4 和 IPV6,目前常见IPV4。
IPV4 由32位二进制数构成,分为4段,范围肯定就是0.0.0.0——255.255.255.255
咯,没问题吧?
IP地址呢又被分为两部分,前部分叫网络部分,后部分叫主机部分,暂时不知道各自占几段哈。
如果A B两电脑在同一子网,那么要求AB的网络部分相同,问题来了,怎么区分网络部分和主机各占多少呢? -
又来一个打辅助的了————子网掩码,掩码也是32位二进制,规定掩码网络部分二进制全为1,主机部分全为0;
掩码是有了,怎么辅助呢?掩码的特点,网络部分全为1,那我们岂不是直到网络占多少位了嘛?
那借用掩码和自身IP进行与(and)运算,是不是就知道IP地址的网络占多少位了?然后两个IP再比较各自网络是否相同。
解决了两台电脑在同一子网的问题,那如果不在同一子网呢?不在同一子网,我们将数据包发给网关
网关帮我们进行转发并传送。
- DNS服务器:全世界这么多网络,每一个主机有一个IP,能记得住吗?记不住的,所以就有了DNS服务器
这玩意就负责解析IP和域名。啥叫域名?www.baidu.com
这就叫域名,是不是有了它就方便多了?
至于到底怎么解析的,本文暂不介绍,后期补上。
综合:通过网络层,我们是不是就可以找到另外一台电脑是否和我们处于同一子网了??我们也就知道他的位置了嘛。
5.传输层:
经过物理层、数据链路层、网络层,我们可以将A的数据传给B了,但B电脑有100个程序,发给谁呢?
这个时候就安排了一个叫“端口(port
)”的家伙上场了,也就是说我们在A给B传数据的时候,还要指定端口。
也就是说其实传输层就是建立端口到端口的通信,要注意区分网络层是主机到主机的通信
不要怀疑为什么你平时输IP没写端口,因为那是已经默认了。比如http
的传输默认端口是80;
6.应用层:应用层就是最接近用户的,传输层传送了很多数据,各式各样的格式,看不懂怎么搞?
不要急,按照一定的数据格式规则进行就好了,它是给软件提供方接口,让程序能使用网络服务。
应用层提供的服务包括文件传输、文件管理以及电子邮件的信息处理等。
2. TCP/IP模型
TCP/IP 是一个复杂的协议族,是由一组专业化协议组成。TCP/IP模型将OSI简化成 4 层,从而有利于实现和高效通信。TCP/IP模型 与 OSI模型
OSI参考模型 --------------------------------------------------------------------TCP/IP模型
应用层——————<高层>:应用于不同的软件 -------------------------->应用层
表示层——————<高层>:数据格式转换 -------------------------------> 应用层
会话层——————<高层>:找到传输层并调用,进行传输 ----------->应用层
传输层——————<低层>:数据打包并发送----------------------------->传输层
网络层——————<低层>:寻找发送路线-------------------------------->网络层
数据链路层————<低层>:参数差错处理、屏蔽硬件差异 ---------->网络接口层
物理层——————<低层>:解决不同硬件间的通信 ------------------->网络接口层
-
网络接口层:
TCP/IP 的最底层,负责将二进制流转化为数据帧,并进行数据帧的发送和接收,数据帧是网络传输的基本单元 -
网络层:
网络层负责在主机之间的通信中选择数据包的传输路径,即路由;
网络层还负责处理传入的数据包,验证其有效性。最后,网络层还要根据需要发出和接收(ICMP)差错和控制报文 -
传输层:
传输层负责实现应用程序之间的通信服务,这种通信又称为端到端通信。 -
应用层:
应用层是分层模型的最高层。应用程序使用相应的应用层协议,把封装好的数据提交给传输层或从传输层接收数据并处理
3. TCP/IP模型特点
-
边界特点:模型中存在一个地址上的边界,它将低层网络的物理地址与网络层的IP地址分开
该边界出现在网络层与网络接口层之间。
1.地址边界特性:它将IP逻辑地址与底层网络的硬件地址分开;
2.操作系统边界特性:它将网络应用与协议软件分开 -
IP层特性:
IP层作为通信子网的最高层,提供无连接的数据包传输机制,但IP协议并不能保证IP包传递的可靠性 -
TCP/IP 的可靠性特性:
TCP 提供面向连接的服务,因为传输层是端到端的,所以TCP/IP的可靠性被称为端到端可靠性。
综合:TCP/IP 的特点就是将不同的低层物理网络、拓扑结构隐藏起来,向用户和应用程序提供通用、统一的网络服务。
TCP/IP 网络完全撇开了底层物理网络的特性,是一个统一的整体。
4. TCP
1.TCP :主要应用于账户、要求比较高,实时性要求不高的地方。
TCP 向应用层提供可靠的、面向连接的数据流传输服务,提供高可靠性通信服务。
高可靠性:数据无误、数据无丢失、数据无时序、数据无重复到达
通过源/目的IP 可以唯一的区分网络中的两个设备,再通过源/目的端口可以唯一区分网络中两个通信的应用程序
IP:就像身份证号,IPV4是32位的, 4*8,即 4 个0-255数字组成,IP是分配给网卡的。
域名:IP不好记,域名就像姓名,比IP好记。将域名转成IP,需要DNS
服务器的支持。
端口:{ 为了在一台设备上可以运行多个程序,人为的设计了端口(Port
)的概念,类似的例子是公司内部的分机号码。
规定一个设备有216
个,也就是65536
个端口,每个端口对应一个唯一的程序。
每个网络程序,无论是客户端还是服务器端,都对应一个或多个特定的端口号。
由于0-1024
之间多被操作系统占用,所以实际编程时一般采用1024以后的端口号。
}
2.TCP的三次握手:
TCP 是面向连接的协议,所谓面向连接就是当计算机双方通信时,必须先建立连接,然后进行数据通信,最后关闭连接。
TCP 在建立连接时候包括 3 个步骤:
1.A->B:主机A(客户端)向主机B(服务器)
发送一个包含SYN
标志的TCP报文,并进入SYN_SEND
()状态,等待服务器确认
2.B->A:主机B(服务器)向主机A(客户端)
主机B在收到客户端的SYN
报文后,将返回一个SYN+ACK
的报文表示B的SYN
被确认,服务器进入SYN_RECV
状态
3.A->B:主机A(客户端)向主机B(服务器)
客户端收到服务器SYN+ACK
报文后,向服务器发送确认ACK
报文,客户端和服务器进入ESTABLISHED
状态,完成TCP连接
注意:刚开始客户端是close状态,服务器处于listen状态。
1.第一次握手:客户端给服务器发送一个SYN
报文,并指定客户端的初始化序列ISN(c)
,此时客户端进入SYN-Send
状态
2.第二次握手:服务端收到客户端发送来的SYN
报文后,会将自己的SYN
报文进行回应,并且也会指出自己的ISN(s),
同时,还会将客户端发来的ISN(c)+1
作为ack
进行回复,表明以收到报文,服务器进入SYN-RECD
状态
3.第三次握手:客户端收到服务器的SYN
后,会发送服务器ISN(S)+1
作为ack
回应,表明已收到报文,并进入established
状态
4.服务器收到ack
后,也处于established
状态,双方连接建立。
简化:
第一次握手:客户端_____SYN(c)(+ISN(c))
______>服务器;
第二次握手:服务器_____SYN(s)(+ISN(s)) + ACK(s)(ISN(c)+1)
_____>客户端;
第三次握手:客户端_____ACK(c)(ISN(s)+1)
______>服务器
三次握手的好处:
1. 确认双方的发送能力、接受能力是否正常
2. 指定自己的初始化序列号ISN,为后面的可靠传送做准备
注意:1. ISN(初始化序列号)是随机的,动态生成的。
2. 三次握手过程中,第三次是可以携带数据的,第一次第二次不可以携带。
想想为什么?因为第一次如果携带数据,第一次是客户端请求服务器,如果有人恶意攻击服务器,那攻击装只需要
在第一次握手中携带大量数据,然后不停地攻击,就可以大量浪费服务器资源了。
第三次可以携带,此时都是established状态,对于客户端来讲,已经知道服务器接收、发送能力都没问题。
3.TCP的四次挥手:
首先,客户端和服务器都是established
状态,假设客户端选择断开:
1. 第一次挥手:客户端给服务器发送一个FIN
报文,报文指定一个序列号(前面受到信息的最后一个字节的序号+1),
此时,客户端处于FIN_WAIT1
状态;
-
第二次挥手:服务端收到
FIN
报文后,会发送ACK
(客户端序列号+1)报文,且将服务器的序列号发送
表明已收到客户端的报文,此时服务器处于CLOSE_WAIT
状态;
客户端收到服务器的FIN报文后,客户端进入FIN_WAIT2
状态,等待服务器发送最后的数据。 -
第三次挥手:服务器向客户端发送
FIN
报文,指定自己序列号,然后服务器进入LAST_ACK
状态,等待客户端回应 -
第四次挥手:客户端收到
FIN
报文后,发送ACK
(服务器序列号+1)作为回应,客户端进入TIME_WAIT
状态简化:
第一次挥手:客户端_______>FIN
报文(含序列号©) _______> 服务器
客户端(established
)——————————>客户端(FIN_WAIT1
)(终止等待1)
服务器(established
)——————————>服务器(established
)第二次挥手:服务器 _______>
ACK
报文(序列号©+1)+序列号(s) _______> 客户端
服务器(established
)——————————> 服务器(CLOSE_WAIT
)
客户端(FIN_WAIT1
) ——————————> 客户端(FIN_WAIT2)
(终止等待2)第三次挥手:服务器 _______>
FIN
报文(含序列号(s)) _______> 客户端
服务器(CLOSE_WAIT
)——————————> 服务器(LAST_ACK
)(最后确认)
客户端(FIN_WAIT2
) ——————————> 客户端(FIN_WAIT2
)第四次挥手:客户端_______>
ACK
报文(序列号(s)+1) _______> 服务器
客户端(FIN_WAIT2
) ——————————> 客户端(TIME_WAIT
)(时间等待)
服务器(LAST_ACK
) ——————————> 服务器(CLOSE
)等时间 =
2*MSL(
最长报文段寿命)客户端(
TIME_WAIT
) ——————————> 客户端(CLOSE
)
4.注意:
1. 此刻TCP还没关闭,还需要确保服务器收到客户端ACK后才会进入CLOSE状态。
需要多久时间呢进入CLOSE
状态呢?
对于服务器,收到客户端ACK
就关闭,对于客户端,需要2*MSL
(最长报文寿命)才关闭。
所以,服务器比客户端先关闭。
2.为什么客户端还需要2*MSL时间?
MSL
指一个片段在网络中最大的存活时间,2*MSL
就是一个发送和一个回复所需的最大时间。
如果直到2*MSL
,客户端都没有再次收到服务端的FIN
,那么客户端推断ACK
已经被成功接收,则结束TCP连接。
3.为什么连接时候是三次握手,断开要四次挥手?
因为当服务器当时是listen状态,客户端是close
状态,服务器收到客户端的SYN报文后,
可以直接发送SYN+ACK
报文, ACK
用来应答,SYN
用来同步。
但在断开连接时候,双方都是established
状态,客户端发送FIN报文只是告知服务器客户端没有数据发送了(1),
此刻的服务器并不一定没有数据需要往客户端发送,可能还有点数据没发完呢?所以服务器发送的ACK
只是告诉
客户端“我收到你的FIN
了”(2),等服务器数据发完了,服务器发送FIN
报文(3),然后等客户端回应。
客户端回应(4)后服务器直接关闭,客户端还需要等一段时间,如果没收到FIN
则关闭。
4.如果已经建立连接,客户端突然出故障怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。
服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,
若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。
若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
5. UDP
UDP即用户数据包协议,是一种面向无连接的、不可靠的传输协议,
消耗资源小、速度快,适用于实时性要求高的地方。
UDP在同心之前不需要建立连接,只能用于发送小尺寸数据,
用于广播、组播、无线网络,多媒体软件等
协议选择:
1. 数据可靠性要求高:TCP
2. 实时性要求高: UDP
3. 网络状态好: UDP,网络状态不好:TCP
6. 网络编程基础
套接字(Socket
):套接字是linux下的一种文件,也是一种特殊的I/O接口,也是一种文件描述符。
socket
不仅能实现本地不同进程能够间的通信,也能通过网络实现不同主机之间的通信。
想想linux
下还有哪些文件,分别用什么符号代替?
复习一下:
Linux下文件分七种,各自符号如下:( ls -l
)
上一篇文章我写成了6种,将设备混在一起了,现在进行更正。
普通文件 --------------------( - )
目录文件 -------------------- d
管道文件 -------------------- p
套接字文件 ----------------- s
块设备文件 ----------------- b
字符设备文件 -------------- c
符号链接文件 -------------- l
既然socket是文件描述符,那怎么获取socket文件描述符呢?
跟管道一样,那管道怎么获取的呢?( int fd = socket( )
);
socket通过函数创建,并返回一个整形额socket描述符,之后的操作都是利用socket文件描述符
-
套接字类型:
1. 流式套接字(SOCK_STREAM)
流式套接字提供可靠的、面向连接的通信流,保证数据的可靠性和按序发送。典型: TCP -
数据报套接字(
SOCK_DGRAM
)
数据报套接字实现了一种不可靠、无连接的服务。
数据通过相互独立的报文发送,且无序。典型:UDP -
原始套接字(
SOCK_RAW
)
原始套接字允许对底层协议进行直接访问,功能强大但不方便。典型: ping命令
2.IP地址:
在前面 OSI模型的网络层中我们已经讲过 IP的基础知识了,现在进行稍微的延伸一下。
1.IP地址的作用:
IP地址用来表示网络中的一台主机。根据协议版本的不同,分为 IPV4 和 IPV6 两种。
一个IP地址分为 2 部分: 1. 网络部分 2. 主机部分
网络号和主机号根据掩码来进行区分。 (IPV4)IP 和掩码都是32位二进制数,但规则不一样。
2.IP地址格式转换:
1. 格式分类:
1.十进制点分形式 : 用户熟悉的形式:192.168.2.219
2.32位二进制形式 : 网络传输中IP地址的存储方式
-
IPV4转换函数:
IPV4地址转换函数有inet_aton()、inet_addr()、inet_ntoa();
IPV4和IPV6兼容函数inet_pton()、inet_ntop();
-
inet_addr
和inet_pton()
函数是将十进制点分形式转换为二进制形式 -
inet_ntop
是inet_pton
的反向操作,将二进制地址形式转为十进制点分形式 -
inet_ntoa()
:将32位网络字节二进制地址转换为点分十进制的字符串、字符串 -
int inet_addr( const char * strptr)
参数:strptr
: 要转换的 IP地址字符串("192.168.2.254
")
返回值:1.成功:32位二进制IP地址(网络字节序) 2.失败:-1 -
int inet_pton( int family, const char * src, void * dst)
参数:family: 1:AF_INET
(IPV4协议)
2:AF_INET6
(IPV6协议)
src:
要转换的 IP地址字符串
dst:
存放转换后的地址的缓冲区
返回值:1. 成功:0 2.出错:-1 -
int inet_ntop( int family, void * src, char * dst, size_t len)
参数:family: 1:AF_INET
(IPV4协议)
2:AF_INET6
(IPV6协议)
src:
要转换的二进制IP地址
dst:
存放十进制地址字符串的缓冲区
len:
缓冲区的长度
返回值:1. 成功:dst
2.出错:NULL
-
7.端口
端口到底是什么东西?怎么用?
- 端口(号)是一个无符号整形(
unsigned short
),取值范围0--65535
(2的16次方-1) - 端口号是系统的一种资源,
0--1023
一般被系统所调用 - TCP 端口号与 UDP端口号互不影响,相互独立
- IP 用来表示网络中的一台主机,端口号则可以用来表示主机内部的某个套接字
即:当创建好一个套接字时,需要将它和某个IP和端口号进行绑定,这样才能实现端到端通信
8.字节序
字节序又称主机字节序(HBO),是指计算机在多字节整形数据的存储方式。
字节序分为两种: 1. 大端 2. 小端
1.大端:高位字节存储在低位地址,低位字节存储在高位地址
2.小端:高位字节存储在高位地址,低位字节存储在低位地址(PC常采用)
大小端是针对多字节存储的,一个字节不存在大小端。字符串也不存在大小端。
在网络通信中,统一规定:数据以高位字节优先顺序在网络上传输————————大端
所以数据在发送前和接收后都需要在主机字节序和网络字节序之间转换
字节序转换函数:
1. uint16_t htons( unit16_t, hostshort)
——————————主机->服务器<短>
hostshort
: 主机字节序的 16bit
数据
2. unit16_t ntohs( unit16_t, netshort)
——————————服务器->主机<短>
netshort
: 网络字节序的 16bit
数据
3. unit32_t htonl( unit32_t, hostlong)
——————————主机->服务器<长>
hostlong
: 主机字节序的 32bit
数据
4. unit32_t ntohl( unit32_t, netlong)
——————————服务器->主机<长>
netlong:
网络字节序的 32bit
数据
解释: h: host; n: network; s: short l: long
成功: 返回转换后字节序的数值 失败:-1
通常 16bit
的IP端口号使用 htons()
和ntohs()
,而IP地址用 htonl()
和 ntohl()
这四个函数只是使其得到相应的字节序,用户不需要知道系统主机字节序和网络字节序是否相等。