网络基础
网络体系结构
定义:是指网络的分层模型和每层所使用的协议的集合
OSI
OSI七层模型:应用层 表示层 会话层 传输层 网络层 数据链路层 物理层是(理想化的模型)
TCP/IP四层模型
应用层 传输层 网络层 物理层(实际使用)
对于以上两种模型来说,除了物理层没有协议,其他各 层都有对应的协议去完成该层相应的功能。
IP地址
IP地址: 在网络中唯一标识一台主机的符号
唯一标识一台主机的符号是MAC地址(硬件地址)
现在使用的IP地址是IPv4协议维护的IP地址。
ipV4维护的IP地址宽度是4个字节。
4个字节的IP地址可表示的地址范围是:
0000 0000*4~1111 1111*4
可以分成5类:
A类:1.0.0.1~126.255.255.254
B类:127.0.0.1~191.255.255.254
C类:192.0.0.1~223.255.255.254(用户地址)
D类:224.0.0.1~239.255.255.254 (组播&多播地址)
E类:240以后
C类=24bit网络号+8bit主机号
网络协议
定义:通信双方对某种通信规则的约定
协议: 通用的网络协议 TCP/IP协议栈(OS)
行业内部专用协议 协议开发
自定义协议
端口号
作用:用来区分应用进程
端口号是一个无符号的整数,范围:1~65535,1~1023已经被占用
字节序
主机字节序:是指不同的CPU主机存贮多字节整数的方 式,有大端序主机和小端序主机
大端序主机:数据的高字节存放在内存的地地址
小端序主机:数据的高字节存放在内存的高地址
主机字节序---->网络字节序
Htonl, Htons(转换 IP地址)
多字节整数发送前要从主机字节序转化成网络字节序, 以适配对端的网络主机
网络字节序:大端序
物理层
物理层是对网络传输介质的抽象,目的是屏蔽掉那些上层不需要知道的差异。个人理解:
① 物理层的主要任务为确定与传输媒体的接口有关的一些特性;
② 另外,数据在计算机中多采用并行传输方式,但数据在通信线路(传输媒体)上的传输方式一般都是串行传输(这是出于经济上的考虑),即逐个比特按照时间顺序传输。因此物理层还要完成传输方式的转换。
由于物理连接的方式很多(例如,可以是点对点的,也可以采用多点连接或广播连接),而传输媒体的种类也非常之多(如架空明线、双绞线、对称电缆、同轴电缆、光缆,以及各种波段的无线信道等),所以具体的物理层协议种类较多。
数据链路层
数据链路层有三个基本问题:封装成帧、透明传输和差错检验。
数据链路层的数据传输单元:帧。在一段数据的前后分别添加首部和尾部,这样就封装构成了一个帧(framing)。
所谓透明传输,是指在数据链路层能透明传送数据,这里透明表示无论什么样的比特组合的数据都能够通过这个数据链路层。
为了保证数据传输的可靠性,在计算机网络传输数据时,必须采用各种差错检测措施。目前在数据链路层广泛使用了循环冗余检验CRC(Cyclic Redundancy Check)的检错技术。注意到,加入冗余码以进行差错检验是建立在在传送数据时以帧为单位来传送的机制上的。因此,如果要在数据链路层进行差错检验,就必须把数据划分为帧,每一帧都加上冗余码,一帧接一帧地传送,然后在接收方逐帧进行差错检验。
这里注意,我们现在并没有要求数据链路层向网络层提供“可靠传输”的服务。
点对点协议PPP (Point-to-Point Protocol)则是目前使用得最广泛的数据链路层协议。
网络层(IP层)
IP层是第一个重点。IP层作用是对数据报文进行地址寻址,告诉数据报文应该去哪。
对分组(待传输的数据)转发的算法归纳如下:
① 从IP数据报的首部提取目的主机的IP地址D,得出目的网络地址为N。
② 若目的主机在本局域网内:若N就是与此路由器直接相连的某个网络地址,则进行直接交付,不需要再经过其他的路由器,直接把数据报交付目的主机(这里包括把目的主机地址 D 转换为具体的硬件地址MAC,把数据报封装为MAC帧,再发送此帧);
③ 若目的主机在路由表内,路由直接相连:若路由表中有目的地址为D的特定主机路由,则把数据报传送给路由表中所指明的下一跳路由器;
④ 若目的主机在路由表内,路由不是直接相连:若路由表中有到达网络N的路由,则把数据报间接交付,传送给路由表中所指明的下一跳路由器;
⑤ 若目的主机在路由表内找不到:若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
⑥ 若还是找不到:报告转发分组出错。
这里有几个注意点:网络在发送分组时不需要先建立连接,网络层不提供服务质量的承诺。同一局域网内,使用地址解析协议ARP来最终找到具体的主机,完成从IP地址到硬件地址的映射。
涉及的重要概念有:IP地址,子网掩码,路由聚合-无分类域间路由选择CIDR (Classless Inter-Domain Routing) 。一个IP地址在整个因特网范围内是唯一的,子网掩码,是用来划分IP地址中哪一部分是网络号,哪一部分是机器号的。CIDR规则的地址有一个后缀说明,表示前缀的位数,例如:192.168.0.0/16,用于解决IP地址耗尽而提出的一种措施。
运输层
运输层是第二个重点,具有代表性的是TCP协议和UDP协议,两种协议在网络数据传输中都是正式协议,没有谁优谁劣区分。
TCP:面向连接,可靠交付,提供全双工通信,面向字节流,时效性弱;
UDP :无连接,尽最大努力交付,不保证可靠交付,面向报文,发送数据报不拆分;没有拥塞控制;首部开销小。
需要注意的是,真正进行通信的实体是在主机中的【进程】,因此,为了区分不同的应用进程,使用了端口号。端口号只具有本地意义,它只是为了标志本计算机应用层中的各个进程在和运输层交互时的层间接口。
TCP的精髓是连续ARQ协议和滑动窗口协议,使用流水线传输,见下图:
发送窗口的意义是:位于发送窗口内分组可连续发送出去,而不需要等待对方的确认;连续ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置,接收方一般都是采用累积确认的方式,这就表示:到这个分组为止的所有分组都已正确收到了。
运输层中,可靠传输的实现:
① 连接管理机制:三次握手与四次挥手。
连接建立过程叫做三次握手(three-way handshake):客户端发起连接请求,第一次握手;服务端发送确认连接报文,第二次握手;客户端发送确认收到确认连接报文的报文,第三次握手。
TCP连接释放过程是四次握手:也称四次挥手。多出来的一次,是确保接收端在收到发送端的信号之后,还能继续发送自己未发送完的数据。发送端在接收到接收端最后的确认之后会再等两个sk,确保自己发送的确认结束字段丢失以后,可以接收到需要重传的的消息。
② 序号和确认序号:
1)TCP会将需要发送的数据按照字节进行编号,这个编号就叫做序号(序列号);
2)当客户端向服务器发送数据,数据会进行编号,如果客户端一次发送的数据的编号是1~1000,若服务器收到客户端发送的数据就会向客户端发送一个确认报文,里面携带一个确认序号是1001,表示1001之前的报文我(服务器)已经收到,下次客户端发送的数据序号就从1001开始;
3)这个服务器对客户端的确认报文里面就将ACK标志位置为1,并且该报文里还携带相应的确认序号,这个确认序号就表明当前我已经收到你发送的哪些数据,下一次你应该从哪里重新发。
③ 确认应答和超时重发:
1)当客户端向服务器发送数据时,超过一段时间,发送端发现还没有收到服务器发来的ACK,客户端就会重新发送数据包。
2)还有一种情况是,服务器收到客户端发来的数据包并发送了相应的ACK报文,但是ACK报文在传输的过程中丢了,同样超过一段时间后,客户端会重新发送相应的数据包时,服务器就会收到两个同样的数据包,但是由于TCP报头里面含有序号,就会对相同的数据包进行去重,这样就保证了数据包能够正确被对方收到。
3)超时时长的确定:超时的时间不能太长也不能太短,太长就会使得效率变慢,等待时间边长;时间太短就会容易出现接收端多次收到重复的包。
操作系统会动态计算这个时间,一般是500ms,当超过500ms还没有收到对方的确认报文,那么就会进行重发,如果重发后还没有收到确认报文,再过2倍的500ms进行重发,每首到然后4倍的500ms时间进行重发,当发送超过一定数量限定的时候,就不再重发,TCP会认为网络出现问题或者连接异常,就会断开连接。
④ 窗口控制:滑动窗口和累计确认机制
⑤ 校验和:TCP校验和是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。
通过以上等等机制,可以实现可靠性传输
应用层
在运输层协议之上,还需要有应用层协议(application layer protocol)。
这是因为,每个应用层协议都是为了解决某一类应用问题,而问题的解决又必须通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。应用进程之间的这种通信必须遵循严格的规则,应用层的具体内容就是精确定义这些通信规则。
应用层协议较多,例如:文件传输,电子邮件,文件服务,聊天软件,视频播放等各种软件应用,对应的常用的协议有FTP、TFTP、SNMP、SMTP、DNS、Telent等。作用在于产生数据报文。
基于TCP协议的网络客户端和服务端模型
服务端:socket-->bind-->listen-->accept-->IO函数
客户端:socket-->connect-->IO函数
int socket(int domain, int type, int protocol);
作用:创建一个网络软通道
domain:协议域 使用AF_INET--》ipv4协议
type:套接字类型
protocol:协议 0--》自动匹配必要的协议
返回值:文件描述符--》用来标识socket通道
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
作用:给套接字绑定网络终端主机信息
sockfd:文件描述符--》socket的返回值
*addr:指向网络终端主机信息的结构体指针
addrlen:struct sockaddr的大小
返回值:0 成功 -1 失败
int listen(int sockfd, int backlog);
作用:侦听--》有没有客户端连接
sockfd:文件描述符--》socket的返回值
backlog:最大侦听客户端的个数
返回值:0 成功 -1 失败
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用:接收客户端的连接请求
sockfd:文件描述符
*addr:用来存放客户端的主机地址信息
*addrlen:第二个参数的长度
返回值:成功,返回新的文件描述符--》标识一个新的IO通道(用于收发正文数据)
失败,-1
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收数据
sockfd:文件描述符--》accept的返回值
*buf:接收数据的存放buf
len:期望接收的字节数
flags:阻塞或非阻塞的标识。0--》阻塞接收
返回值:成功,>0 接收到的字节个数
<=0 失败
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:发送数据
sockfd:文件描述符--》accept的返回值
*buf:要发送数据
len:期望发送的字节数
flags:阻塞或非阻塞的标识。0--》阻塞接收
返回值:成功,>0 接收到的字节个数
-1 失败
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:连接服务端
sockfd:文件描述符--》socket的返回值
*addr:服务端主机的地址信息
addrlen:第二个参数的长度
返回值:0 成功
-1 失败
TCP的三次握手与四次挥手
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如ip地址、端口号等。TCP可以看成是一种字节流,它会处理IP层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在TCP头部。一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:连接、数据传输、退出(关闭)。通过三次握手建立一个链接,通过四次挥手来关闭一个连接。当一个连接被建立或被终止时,交换的报文段只包含TCP头部,而没有数据。
在了解TCP连接之前先来了解一下TCP报文的头部结构。
上图中有几个字段需要重点介绍下:
(1)序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
-
ACK:确认序号有效。
-
FIN:释放一个连接。
-
PSH:接收方应该尽快将这个报文交给应用层。
-
RST:重置连接。SYN:发起一个新连接。
-
URG:紧急指针(urgent pointer)有效。需要注意的是:不要将确认序号ack与标志位中的ACK搞混了。确认方ack=发起方seq+1,两端配对。
-
三次握手
三次握手的本质是确认通信双方收发数据的能力首先,我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。于是他给我回信,我若收到了,我便知我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。然而此时他还不知道他的发件能力和我的收件能力到底可不可以,于是我最后回馈一次,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。这,就是三次握手。
-
第一次握手:客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。
-
第二次握手:服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
-
第三次握手:客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。
四次挥手
四次挥手的目的是关闭一个连接
比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。
-
第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
-
第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
-
第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
-
第四次挥手:客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。
常见面试题
为什么TCP连接的时候是3次?2次不可以吗?
因为需要考虑连接时丢包的问题,如果只握手2次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数(可以理解服务端已经连接成功)据,而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端发过来的数据。如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。
为什么TCP连接的时候是3次,关闭的时候却是4次?
因为只有在客户端和服务端都没有数据要发送的时候才能断开TCP。而客户端发出FIN报文时只能保证客户端没有数据发了,服务端还有没有数据发客户端是不知道的。而服务端收到客户端的FIN报文后只能先回复客户端一个确认报文来告诉客户端我服务端已经收到你的FIN报文了,但我服务端还有一些数据没发完,等这些数据发完了服务端才能给客户端发FIN报文(所以不能一次性将确认报文和FIN报文发给客户端,就是这里多出来了一次)。
为什么客户端发出第四次挥手的确认报文后要等2MSL的时间才能释放TCP连接?
这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。
基于UDP协议的客户端和服务端模型
服务端:socket-->bind-->IO函数(recvfrom/sendto)
客户端:socket-->IO函数(sendto/recvfrom)
两种网络编程框架的对比:
1 特点
TCP:使用流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内部设置了流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
UDP:使用数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)--ping.c
可以对较低层次协议如IP、ICMP直接访问
2 协议
TCP(传输控制协议):
TCP是一个可靠的,全双工的,有序的,面向链接的字节流通信的协议。
为什么可靠:
1.丢失的数据包重发 (能保证拿到数据)
2.错误的数据包重发 (保证能拿到正确的数据)
3.数据的有序到达(因为对每个数据包进行了编号)(拆包,编 号)
4.有较为健全的校验机制(为了保证数据的正确性)
5.支持面向连接(保证通信线路的畅通)-->三次握手
6.有信道拥堵控制(通过一种对于信道拥堵解决的方案,来提高转发效率)
为什么有序(有序列号):
1.保证数据都能传输给对端,不至于当传输的数据 > 信道带宽,导致数据丢弃。
2.通过序号,在对端主机上可以拼接成原本的数据包
3.保证数据传输的可靠性
如何面向链接:
三次握手和四次挥手
UDP:
UDP(The User Datagram Protocol):无连接的数据报协议,别名"不可靠的协议"
<1>使用校验和来实现错误侦测
<2>UDP常用于媒体流的传输(音频、视频、等),在这种情况下,实时性比可靠性更重要
<3>UDP也常用于简单的查询/回应程序,例如DNS查找,在这种情况下,建立可靠传输的资源消耗太大
<4>UDP是一种实时传输协议(Real-time Transport Protocol),这种协议通常用来传输实时数据例如:音视频流
不可靠的原因:
1.非面向连接(不关心接收端是否在线)--》没有三次握手
2.丢包不重发
3.错误的包不重发
4.没有信道拥堵控制
5.有一个最大传输长度限制
6.没有严格的校验机制
如何抉择使用TCP还是UDP?
1.可靠性
2.实时性
可靠性 > 实时性: TCP
可靠性 < 实时性: UDP
IO模型
阻塞IO
若要读的数据没有准备好,或要写入的目标没有空间,将会发生读写阻塞
常见的阻塞IO函数:recv recvfrom read write send accept connect
非阻塞IO
若要读的数据没有准备好,IO函数返回一个约定的错误值,不阻塞当前进程 ,可以通过循环去多次尝试读取数据。
常见的非阻塞IO函数:read/write(可以通过修改底层驱动设 计成非阻塞)
IO多路复用
思想:
1 构建一张文件描述符集合表,表的大小为1024bit,这些bit分别对应的是1024个文件描述符,这些bit位中存放的数据表示的是该描述符对应的IO通道是否有数据发生(1 有数据;0 没有数据) int a[32]--->1024Bit
2 使用 select监测程序中的文件描述符对应的通道是否有IO数据发生?若有IO数据发生,将文件描述符集合表的相应Bit位置1,同时将其他的bit位置0,并返回监测到的文件描述符的通道个数。
3 对监测的结果做出判断和响应。
循环遍历文件描述符集合表,查看集合表中关心的描述符对应的BIT位是否是1?如果是1,响应这路IO;如果是0,继续循环
int select(int n, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
作用:监控文件描述符对应的IO通道是否有数据
N:最多监控多少个通道
*read_fds:指向读文件描述符集合表
*write_fds:指向写文件描述符集合表
*except_fds:指向异常文件描述符集合表
*timeout:NULL---》阻塞监控
返回值:select监控到的有数据发生的IO通道的个数
为了设置文件描述符我们要使用几个宏:
FD_SET 将fd加入到fdset
FD_CLR 将fd从fdset里面清除
FD_ZERO 从fdset中清除所有的文件描述符
FD_ISSET 判断fd是否在fdset集合中
If(FD_ISSET(0,stFdr))
{响应0对应的通道数据 fgets();}
服务器模型
服务器:可以服务于多个客户端的服务程序
种类:循环服务器和并发服务器
循环服务器:指的是该服务程序可以服务于多个客户端, 但是在同一时刻只能服务一个客户端。while
并发服务器:指的是该服务器可以在同一时刻服务于多个 客户端
在linux系统中,实现并发服务器,可以使用:
多进程 多线程 select poll epoll
多进程
思想:主进程专门用于连接多个客户端,若有一个客户端接进来,就创建一个子进程来负责该客户端的业务数据的收发 。
多线程
思想:主进程专门用于连接多个客户端,若有一个客户端接进来,就创建一个子线程来负责该客户端的业务数据的收发 。
select-->IO多路复用
思想:
1 构建一张文件描述符集合表,表的大小为1024bit,这1024个bit位用来存放1024个文件描述符对应的IO通道是否有数据发生,有数据发生的通道对应的BIT位置1,没数据发生的通道对应的BIT位置0。--》空表
2 使用select函数去监控关注的文件描述符对应的通道是否有数据发生?若监控到一路或多路通道有数据发生,则返回通道的路数同时将有数据发生的通道对应的文件描述符集合表的相应BIT位置1,同时将其他BIT位置0
(监控 置位)
3 对文件描述符集合表中的置位结果做出判断和响应。使用FD_ISSET去判断关心的描述符是否被置位了,若被置位了,返回真,那么响应这路IO;若没有被置位,返回假,不做处理。
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
作用:监控文件描述符对应的IO通道是否有数据发生
参数1:监控的最大通道个数
参数2:指向读文件描述符集合表的指针
参数3:指向写文件描述符集合表的指针
参数4:指向异常文件描述符集合表的指针
参数5:timeout=0,只检测文件描述符集合的状态,然 后立即返回
Timeout=NULL,select函数阻塞监控关注的文件 描述符通道
Timeout=时间,时间到达之间select函数一置阻 塞监控,时间到,结束监控。
返回值:成功返回监控到有数据发生的IO通道的个数
失败 -1
网络服务器超时检测
1.select超时设置---->select
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
Timeout:超时时间,若在指定的时间内没有客户端连接该服务器,服务器会一直阻塞,当指定时间到时,没有客户端连接,select阻塞时间到,返回0。
2 使用信号和alarm
Signal(信号,信号对应的新的处理函数)--》set
Sigaction(信号,NULL,&act) --->/get获取信号对应的旧的处理动作
Sigaction(信号,&act,NULL)-->set 设置信号对应的新的处理动作
void handler(int signo) { return; }-->新的处理函数
struct sigaction act;--》信号对应的处理对象
sigaction(SIGALRM, NULL, &act);--》获取信号旧的处理对象信息
act.sa_handler = handler;--》设置对象新的处理函数
act.sa_flags &= ~SA_RESTART;--》设置对象的重启标志为不重启
sigaction(SIGALRM, &act, NULL);--》设置信号对应的新对象
alarm(5);--》启动定时器,定时5S
3.设置socket属性
Setsockopt:设置套接字的属性
Getsockopt:获取套接字的属性
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv));
广播&组播
在网络中,数据包的发送方式有三种:单播 广播 组播
广播:数据发送方将数据包发送给了局域网中的所有的主机。
广播地址通常是这个网段中最大的IP地址,
例如192.168.12.255或者是255.255.255.255
广播发送:socket-->setsockopt(允许广播发送) --》sendto(广播地 址) udp_client.c
广播接收:socket-->bind-->recvfrom udp_server.
组播:数据发送方将数据包发送到了某个主机的组播组里,加入 到该组播组的所有的主机能够接收到组播数据
组播地址:224.0.0.1~239.255.255.254
组播发送:socket-->指定目标地址为组播地址--》sendto
组播接收:socket-->加入组播组--》bind->recvfrom
加入组播组:
unix域套接字-->socket文件->通信介质
unix域:socket文件(使用本地协议创建的socket文件)
用socket函数使用本地协议可以创建一个socket文件,通过该文件能够实现一台主机上两个进程的通信。
unix域套接字有两种:流式套接字 数据报套接字
TCP流式套接字:
使用TCP协议的网络编程框架创建流式套接字文件,该套接字文件可以实现一台主机上两个本地进程的通信。
服务端:socket--》bind-->listen-->accept-->IO函数
客户端:socket-->connect-->IO函数
注意:tcp方式的unix域套接字,类似无名管道,实现双向通信只需要一个文件。可以实现两个不相关进程的通信
UDP数据报套接字:
使用UDP协议的网络编程框架创建数据报套接字文件,该套接字文件可以实现一台主机上两个本地进程的通信。
发送方:socket-->bind-->IO函数
接收方:socket-->bind--》IO函数
注意:udp方式unix域套接字,类似于有名管道,实现双工通信需要两个管道文件。用于两个不相关进程的通信