[ 网络 ] 传输层协议——TCP/UDP

目录

再谈端口号

端口号范围划分

netstat

 pidof

UDP协议

UDP协议端格式

UDP的特点

面向数据报

UDP的缓冲区

UDP使用注意事项

基于UDP的应用层协议

TCP协议

TCP的特点及其目的

TCP协议段格式

可靠性问题

确认应答机制(ACK)

超时重传机制

重发超时如何确定

流量控制

连接管理——3次握手 4次挥手 

tcp三次握手

tcp四次挥手

验证CLOSE_WAIT状态

listen的第二个参数

验证TIME_WAIT状态

解决TIME_WAIT状态引起的bind失败的方法

滑动窗口

拥塞控制

延迟应答

捎带应答 

面向字节流

粘包问题

UDP是否存在粘包问题?

TCP异常情况

用UDP实现可靠传输

TCP小结

基于TCP应用层的协议


传输层负责数据能够从发送端传输到接收端。TCP/IP中有两个具有代表性的传输层协议,分别是UDP和TCP。TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。总之,根据通信的具体特征,选择合适的传输层协议是非常重要的。

再谈端口号

端口号(Port)标识了一个主机上进行通信的不同的应用程序,一台计算机上同时可以运行多个程序。传输层协议正是利用这些端口号识别本机中正在进行通信的应用程序,并准确的将数据传输。

在TCP/IP协议中,"源IP","源端口号","目的IP","目的端口号", "协议号" 这样的五元组来表示一个通信(可以通过netstat -n查看)

端口号范围划分

  • 0-1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,他们的端口号都是固定的
  • 1024-65535:操作系统动态分配的端口号,客户端程序的端口号,就是由操作系统从这个范围分配的

有些服务器是非常常用的,为了使用方便,人们约定一些常用的服务器,都是用以下这些固定的端口号

  • ssh服务器,使用22端口号
  • ftp服务器,使用21端口号
  • telnet服务器,使用23端口号
  • http服务器,使用80端口号
  • https服务器,使用443

cat /etc/services可以查看知名端口号,我们自己写一个程序使用端口号时要避开这些知名端口号。

 一个进程可以bind多个端口号但是一个端口号只能被一个进程bind

netstat

netstat是一个用来查看网络状态的重要工具

常用选项:

  • n拒绝显示别名,能显示数字的全部转化成数字
  • l 仅列出有Listen(监听)的服务状态
  • p 显示建立相关链接的程序名
  • t 仅显示tcp相关选项
  • u 仅显示udp相关选项
  • a 显示所有选项,默认不显示Listen相关

 pidof

再查看服务器的进程id时非常方便,通过进程名,查看进程id

UDP协议

UDP ( User Datagram Protocol )不提供复杂的控制机制,利用IP提供面向无连接的通信服务。并且它是将应用程序发来数据在收到的那一刻,立即按照原样发送到网络上的一种机制。

UDP协议端格式

  • 16位UDP长度,表示整个数据报(UDP首部+UDP数据) 的最大长度
  • 如果校验和出错,就会直接丢弃

前8个字段称为UDP报头,数据叫做有效载荷,如果应用层发送Hello,那么Hello就在数据中。

我们可以看到UDP采用定长报头。那么UDP在封装时,直接在有效载荷前加上UDP报头即可,而在分用的时候,应用层直接提取前8个字节就可以拿到UDP的报头字段。

网络协议栈的tcp/ip协议是内核中实现的,内核使用C语言实现的

struct udp_hdr
{
    unsigned int src_port : 16;
    unsigned int dst_port : 16;
    unsigned int udp_len  : 16;
    unsigned int udp_check : 16;
};

这就是udp报头字段,在C语言中我们称作位段。位段在申请空间的时候会以前面的类型的申请的。因此报文的宽度是0-31 ,因此udp的报头就是8字节。

UDP的特点

UDP传输的过程类似于寄信

  • 无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接
  • 不可靠:没有确认机制,没有重传机制,如果我因为网络故障该端无法发送到对方,UDP协议层也不会给应用层返回任何错误信息
  • 面向数据报:不能够灵活的控制读写数据的次数和数量

面向数据报

应用层交给UDP多长的报文,UDP原样发送,既不会拆分也不会合并

用UDP传输100个字节的数据:如果发送端调用一次sendto,发送100个字节,那么接收端也必须调用一次对应的recvfrom,接受100个字节,而不能循环调用10次recvfrom,每次接受10个字节。

UDP的缓冲区

  • UDP没有真正意义上的发送缓冲区,调用sendto会直接交给内核,由内核将数据传给网络协议进行后续的传输动作
  • UDP具有接受缓冲区,但是这个接受缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致,如果缓冲区满了,再到达的UDP数据就会被丢弃

UDP的socket既能读也能写这个概念叫做全双工

UDP使用注意事项

我们注意到UDP协议首部中有一个16位的最大长度,也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部),然而64K在当今的互联网环境下,是一个非常小的数字,如果我们需要传输的数据超过64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼接。

基于UDP的应用层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议

TCP协议

TCP 全称为 " 传输控制协议 (Transmission Control Protocol"). 人如其名 , 要对数据的传输进行一个详细的控制;TCP与UDP的区别相当大,他充分的实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在UDP中都没有。此外,TCP作为一种面向连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。
根据TCP的这些机制,在IP这种无连接的网络上也能够实现高可靠性的通信。

TCP的特点及其目的

为了通过IP数据报实现可靠性传输,需要考虑很多事情。TCP通过检验和,序列号,确认应答,重发控制,连接管理以及窗口控制等等机制实现可靠性传输。

TCP协议段格式

  • 源/目的端口号:表示数据是从哪个进程来,到哪个进程去
  • 32位序号/32位确认序号:
    • 序列号(32位):是指发送数据的位置。每发送一次数据,就累加一次该数据字节数的大小。序列号不会从0或1开始,而是建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机。
    • 确认序号(32位):确认应答序号长32位,是指下一次应该收到的数据的序列号。实际上,它是指已收到确认应答号前一位位置的数据。发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接受
  • 4位首部长度(数据偏移):该字段长4位,单位字节,实际的大小是15*4 = 60字节,该字段表示TCP所传输的数据部分应该从TCP包的哪个位开始计算,当然也可以把它看做TCP首部长度。因此不包括选项字段的话,TCP的首部长度为20字节长,因此4位首部长度最小设置为5.反之,如果该字段的值为5,那说明从TCP包的最一开始到20字节为止都是TCP首部,余下的部分为TCP数据。
  • 6位保留:该字段主要是为了以后扩展时使用。

可靠性问题

TCP的可靠性有一部分是体现在报头字段的。

1.什么是不可靠?

丢包,乱序,数据包校验失败.....

2.怎么确认一个报文是丢了还是没丢呢?

我们如果收到了应答,我们确认是没丢;否则就是不确定!

比如:你给你朋友发送一条消息:吃了吗?你能确认他收到了吗?其实是不能的。但是如果他给你回复一条:吃了,吃的饺子! 通过他的回复我们可以确认我们刚刚发送出去的消息,对方收到了。因此我们只要得到应答就意味着我们刚刚发送的消息对方100%收到了。

而在长距离交互的时候,永远有一条最新的数据是没有应答的,但是我们只要发送的消息有对应的应答,我们就认为我们发送的消息,对方是收到的 ! 而这个思想就是TCP可靠性的根本思想。这个机制就是确认应答机制

确认应答机制(ACK)

TCP通过肯定的确认应答(ACK)实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端,反之,则数据可能丢失了。

报文中有个序列号字段,序列号是按顺序发送数据的每一个字节都标上好嘛的编号,接收端查询接受数据TCP首部中的序列号和数据的长度,将自己下一步应该接受的序号作为确认应答返回回去,就这样,通过序列号和确认应答好,TCP实习可靠传输

发送的数据

序列号与确认应答号 

当主机A发送数据(1-1000字节),如果主机B收到了这1000个字节,则确认序号为1001,发给主机A,当主机A收到发现确认应答是1001时,主机A就知道前1000字节主机B已经成功收到,就可以继续发送下面的数据了。每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.

那么为什么需要两组序号?为什么既有序号又有确认序号

因为TCP是全双工的,我在给你发消息的同时,我也可以收消息。

举例:客户端给服务端发送消息,序号10;服务器给客户端回消息是也想发送自己的消息,那么也要有自己的序号!因此如果服务器想给你应答的同时也想给客户端发送消息,要应答就要填充确认序号,要发消息就要保证可靠性,因此服务端也需要携带自己的序号!因此需要同时设置,就需要一个序号一个确认序号!

超时重传机制

  • 主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B
  • 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发 

但是主机A未收到B发送来的确认应答,也可能是因为ACK丢失了

由主机B返回的确认应答,因网络拥堵等原因在传输的途中丢失,没有到达主机A,主机A会等待一段时间,若在特定的时间间隔内始终未能收到这个确认应答,主机A会对数据进行重新发送,此时,主机B将第二次发送已接收此数据的确认应答。由于主机B已经收到过1~1000的数据,当再有相同数据送达时它会放弃。而主机B是如何确认这段数据是重复的呢?是通过序号,如果这段数据的TCP报头中的序号我已经收到过,那么就可以确定这段数据重复了。因此序号还有一个作用是去重报文。

重发超时如何确定

重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过了这个时间仍未收到确认应答,发送端将进行数据重发。那么如果超时,时间如何确定呢?

  • 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".
  • 但是这个时间的长短, 随着网络环境的不同, 是有差异的.
  • 如果超时时间设的太长, 会影响整体的重传效率;
  • 如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间。

在Linux中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍'。不过,由于最初的数据包还不知道往返时间,所以其重发超时一般设置为6秒左右。 在BSD的Unix以及Windows系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍‘。不过,由于最初的数据包还不知道往返时间,所以其重发超时一般设置为6秒左右.

数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长。

此外,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

流量控制

数据什么时候发,发多少,出错了怎么办,要不要添加提高效率的策略 -- 都是由OS内TCP自主决定的。因此TCP协议叫做传输控制协议

如果客户端发送的太快了,导致Server来不及接受怎么办?由于服务端接受缓冲区满了,所以多余的报文只能丢弃。但是发送报文都会消耗网络资源,因此我们在发送报文的时候都要根据对端的接受能力发送对应大小的报文。因此就需要让Client知道Server的接受能力。因此Server的接受能力就是由接受缓冲区剩余空间的大小,那么如何让Client知道,因此当server应答时,在TCP报头中有一个保存Server接受能力的属性字段:正是16位窗口大小

  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段, 通过ACK端通知发送端;
  • 窗口大小字段越大, 说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后, 就会减慢自己的发送速度;
  • 如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端
  • 16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么 ?
    实际上 , TCP 首部 40 字节选项中还包含了一个窗口扩大因子 M, 实际窗口大小是 窗口字段的值左移 M ;

 

如果接收端接收缓冲区打满,发送端就不会发送消息,但是会不定期发送窗口探测报文来得知接收端目的主机的实时的接受能力。

连接管理——3次握手 4次挥手 

TCP提供面向连接的通信传输。面向有连接是指在数据通信开始之前做好通信两端的准备工作。

一个连接的建立与断开,正常过程至少需要来回发送7个包才能完成。只有完成了3次握手,才算建立连接成功,才能正式通信!通信完毕之后,需要四次挥手才能断开连接!

站在Server的角度,收到的报文有的是用来建立连接的,有的是断开连接的,有的是用来传输数据的,因此报文也是有类别的!因此作为Server来讲,必须要区别报文的类别!

  1. SYN :只要报文是建立连接的请求,SYN标志位需要设定为1
  2. FIN:该报文是一个申请断开连接请求的标志位,因此SYN和FIN不会同时置位1.
  3. ACK:表示该报文是对历史报文的确认。TCP规定除了最初建立的连接时的SYN包之外该位必须设置为1.

  4. PSH:该为1时,表示需要将受到的数据立刻传给上层的应用层协议。PSH为0时,则不需要立即传而是先进行缓存。

  5. URG:表示包中有需要紧急处理的数据。报文在发送的时候是可能乱序到达的,乱序到达是不可靠的一种,因此需要让报文按序到达就需要序号。所以如果数据是必须在TCP中进行按序到达的话,也就说如果有一些数据优先级更高,但是序号较晚,无法做到数据被紧急处理吗,这样的报文如果想被优先处理,那么把URG标志位设置为1。与之配合的是16位紧急指针,是标定的紧急数据在数据中的标记位的。因此一个报文中的数据并不都是紧急数据,而是16位紧急指针指向的一个字节的数据是紧急数据。

    1. 一般在暂时中断通信,或中断通信的情况下使用。例如在Web浏览器中点击停止按钮,或者使用telent输出Ctrl+C时都会有URG为1的包。此外,紧急指针也用作表示数据流分段的标志

  6. RST:重新连接标志位,下面会解释。

tcp三次握手

为什么要三次握手?

因为tcp是面向连接的,因此在通信之前就必须先建立连接。

三次握手中客户端(主动断开连接的一方)状态转换:

  1. [CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;
  2. [SYN_SENT -> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据

三次握手中服务器端状态转换:

  1. [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接;
  2. [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文.
  3. [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行 读写数据了.

为什么是3次?不是1次?2次?4次?

一次握手 -- 不行:

答案是不行,因为只有一次握手,也就是客户端只给服务器发送一个SYN,那么客户端如果循环给服务端发送SYN,那么服务端要维护此链接,就要消费很多有效资源,那么只需要一套机器,就可以让服务器浪费许多资源--SYN洪水。因此一次连接是肯定不行的。

二次握手 -- 不行:

两次握手时客户端给服务端发送SYN,服务器端回复ACK。其实两次握手和一次握手是一样的效果。当客户端给服务器继续发送SYN洪水,当服务器端接收到请求之后回复一个ACK,也会维护此链接,而服务端给客户端回复的ACK客户端直接丢弃,那么效果就和一次握手很类似了。

三次握手 -- 可以:

一次和两次之所以不行,是因为都是让服务器端先认为链接已经建立好了,而三次握手可以把最后一次确认的机会交给服务器端。也就是说,客户端如果给服务器发送SYN洪水,服务器端要维护这些链接,消耗资源,而回复ACK的时候,客户端也要建立维护链接,再返回ACK给服务器端,因此多一次握手,客户端也要和服务器端一样消耗资源维护链接,服务器端也会把客户端拉下水。因此三次握手即使失败或者非法,可以把最后一次报文丢失的成本嫁接给客户端。

6.RST:如果最后一次ACK丢失,客户端认为链接建立成功,服务器端等待对端回复ACK,服务器端过段时间会超时重传SYN+ACK。那么如果在这段时间,由于客户端认为链接建立成功,客户端已经开始向服务器端发送报文,当服务端收到消息的时候就疑惑?不是连接还没建立完成,怎么消息就来了呢?因此此时服务器端就立马给客户端发来的数据进行ACK响应,并且把RST标志位置为1,告诉客户端让其关闭连接,进行重新连接。

tcp四次挥手

四次挥手中客户端(主动断开连接的一方) 状态转换:
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.

四次挥手中服务端状态转换:

  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器 返回确认报文段并进入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当 服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
  • [LAST_ACK -> CLOSED] 服务器收到了对FINACK, 彻底关闭连接。

为什么是四次挥手

客户端发送的FIN要保证服务器端收到,因此FIN必须要有ACK,因此两个FIN都必须要有ACK,这也就是4次挥手。当客户端和服务器端同时想要断开连接,在服务器端回复ACK的时候同时发送FIN。那么整个挥手过程变成了3次挥手。

验证CLOSE_WAIT状态

CLOSE_WAIT状态是一端想要断开连接,另一方不断开连接,那么另一方就会一直维持在CLOSE_WAIT状态。注意先不能accept.

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cassert>
#include <cerrno>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
class ServerTcp
{
public:
    ServerTcp(uint16_t port,const std::string& ip = "")
        :port_(port),ip_(ip),listenSock_(-1)
        {
            quit_ = false;
        }
    ~ServerTcp()
    {
        if(listenSock_>= 0)
        {
            close(listenSock_);
        }
    }
public:
    void init()
    {
        //1.创建socket
        listenSock_ = socket(PF_INET,SOCK_STREAM,0);
        if(listenSock_ < 0) exit(1);
        //2.bind 绑定
        //填充服务器信息
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty()?(local.sin_addr.s_addr = INADDR_ANY):(inet_aton(ip_.c_str(),&local.sin_addr));
        if(bind(listenSock_,(const struct sockaddr*)&local,sizeof(local)) < 0) exit(2);
        //3.监听
        if(listen(listenSock_,2) < 0) exit(3);
        //让别人来链接你
    }
    void loop()
    {
        signal(SIGCHLD,SIG_IGN);//only linux
        while(!quit_)
        {
            sleep(1);
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);

            int serviceSock = accept(listenSock_,(struct sockaddr *)&peer,&len);
            if(quit_) break;
            if(serviceSock<0)
            {
                //获取链接失败
                std::cerr<<"accept error........." <<std::endl;
                continue;
            }
            std::cout<<"获取新链接成功: "<<std::endl;
        }
    }

    bool quitServer()
    {
        quit_ = true;
        return true;
    }

private:
    int listenSock_;
    uint16_t port_;
    std::string ip_;
    bool quit_;//安全退出
};
#include "server.hpp"

static void Usage()
{
    std::cout << "Usgae:\n\t ./server port" <<std::endl;
    exit(4);
}
int main(int argc,char* argv[])
{
    if(argc != 2) Usage();
    ServerTcp svr(atoi(argv[1]));
    svr.init();
    svr.loop();
    return 0;
}

当运行起来之后,我们可以使用另外一台及其进行对服务器连接(这里不推荐使用一台机器,因此如果是一台机器,服务器和客户端是一台机器,那么我们在查询的时候就会出现两个字段,不方便查看)

启动服务之后,在另外一台机器上链接服务器

此时

我们发现了8082的外部地址是81,正式我们另外一台机器。现在他的状态是ESTABLISHED -- 因此我们得到一个结论,我们现在不accpet,三次握手也会成功。

我们现在让81的机器同时链接4个会怎么样的?

 我们来查看一下状态,发现其中有一个状态是SYN_RECV,我们快快来看看这个状态是什么?

 我们发现,SYN_RECV意味着服务器收到了你连接的请求,但是我先不给你ACK。那么为什么到第四个客户端再连接时就不能完成三次握手呢?这是listen的第二个参数有关。

listen的第二个参数

基于刚才封装的 TcpServer  实现以下测试代码
对于服务器 , listen 的第二个参数设置为 2, 并且不调用 accept
此时启动 3 个客户端同时连接服务器 , netstat 查看服务器状态 , 一切正常 . 但是启动第四个客户端时, 发现服务器对于第四个连接的状态存在问题了

listen的第二个参数叫做底层的全连接队列的长度,算法是:n+1表示在不accept的情况下,服务器最多能够维护的链接个数。因此我们刚刚最多只能有3个客户端同时连接我们

客户端状态正常 , 但是服务器端出现了 SYN_RECV 状态 , 而不是 ESTABLISHED 状态
这是因为 , Linux 内核协议栈为一个 tcp 连接管理使用两个队列:
  1. 半链接队列(用来保存处于SYN_SENTSYN_RECV状态的请求)
  2. 全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求)
而全连接队列的长度会受到 listen 第二个参数的影响 . 全连接队列满了的时候, 就无法继续让当前连接的状态进入 established 状态了 . 这个队列的长度通过上述实验可知, listen 的第二个参数 + 1.

当我们把第一个客户端关闭的时候,我们再来查看状态,我们发现此时,他的状态就变成了CLOSE_WAIT,结合我们四次挥手的流程图, 可以认为四次挥手没有正确完成.

小结:

对于服务器上出现大量的 CLOSE_WAIT 状态 , 原因就是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG. 只需要加上对应的 close 即可解决问题

当全部关闭客户端时,状态便全部变成了CLOSE_WAIT

验证TIME_WAIT状态

现在做一个测试 , 首先启动 server, 然后启动 client, 然后用 Ctrl-C 使 server 终止 , 这时马上再运行 server, 结果是

此时我们立马让服务其CTRL-C

 这是因为虽然server的应用程序终止了,但TCP协议层的连接并没有完全断开,因此不能再次监听同样的server端口。

  • TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL的时间才能回到CLOSED状态
  • 我们使用Ctrl-C终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口
  • MSL在RFC1122中规定是2分钟。但是各操作系统的实现不同, Centos7上默认配置的值是60s。
为什么是 TIME_WAIT 的时间是 2MSL?
  1. MSLTCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);
  2. 同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);

解决TIME_WAIT状态引起的bind失败的方法

server TCP 连接没有完全断开之前不允许重新监听 , 某些情况下可能是不合理的

  • 服务器需要处理非常大量的客户端的连接 ( 每个连接的生存时间可能很短 , 但是每秒都有很大数量的客户端来请求).
  • 这个时候如果由服务器端主动关闭连接( 比如某些客户端不活跃 , 就需要被服务器端主动清理掉 ), 就会产 生大量TIME_WAIT 连接 .
  • 由于我们的请求量很大, 就可能导致 TIME_WAIT 的连接数很多 , 每个连接都会占用一个通信五元组 ( ip, 源端口, 目的 ip, 目的端口 , 协议 ). 其中服务器的 ip 和端口和协议是固定的 . 如果新来的客户端连接的 ip 和端口号和TIME_WAIT 占用的链接重复了 , 就会出现问题 .

解决:

使用 setsockopt() 设置 socket 描述符的 选项 SO_REUSEADDR 1, 表示允许创建端口号相同但 IP 地址不同的多个socket描述符

 

滑动窗口

TCP如果每一个发送数据段,都要给一个ACK的确认应答,收到ACK后在发送下一个数据段,这样做有一个比较大的确定啊,就是性能较差,尤其是数据往返的时间较长的时候。

为了解决这个问题,TCP引入了一个滑动窗口的概念。即使在往返时间较长的情况下,它也能控制网性能的下降。确认应答不再是以每个分段,而是以更大的单位进行确认时,转发时间将会被大幅度的缩短。也就是说,发送端主机在发送一个段以后不必要一直等待确认应答,而是继续发送。

  • 窗口大小指:无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000个字节.(4个段)
  • 发送前4个段的时候,不需要等待任何ACK,直接发送。
  • 收到第一个ACK以后,滑动窗口向后移动,继续 发送第5个段的数据;以此类推
  • 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有那些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉。
  • 窗口越大,则网络的吞吐量就越高

 那么如果出现了丢包,如何进行重传?这里分两种情况讨论

情况一:数据包已经抵达,ACK丢失了。这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认。

 情况二:数据包直接丢了

  • 当某一段报文端丢失之后,发送端会一直收到1001这样的ACK,就像是在提醒发送端"我想要的是1001一样"
  • 如果发送端主机连续3次收到了同样"1001"这样的应答,就会将对应的数据1001-2000重新发送
  • 这个时候接收端收到了1001之后,再次返回的ACK就是7001(因为2001-7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中。

这种机制被称为"高速重发控制"(也叫快重传)。滑动窗口不一定向右滑动,滑动窗口有可能增大也有可能减小。

start_index什么时候会向右走:

start_index等于确认序号;end_index=start_index+窗口大小

拥塞控制

虽然TCP有了滑动窗口这个大杀器,能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题。因为网络上有很多计算机,可能当前的网络状态就已经比较拥堵,在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。

因此为了解决这个问题,TCP引入慢启动机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。

  • 此处引入了一个概念称为拥塞窗口
  • 发送开始的时候,定义拥塞窗口大小为1
  • 每次收到一个ACK应答,拥塞窗口加1
  • 每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口

因此发送方向接收方一次可以发送的数据量 = min ( 对方的接受能力,网络的拥塞窗口 ) 

因此滑动窗口的大小 = min (对方窗口大小的剩余值,网络的拥塞窗口)

因此end_index  = start_index + min(窗口大小,拥塞窗口)

像上面这样的拥塞窗口增长速度 , 是指数级别的 . " 慢启动 " 只是指初使时慢 , 但是增长速度非常快 .
  • 为了不增长的那么快 , 因此不能使拥塞窗口单纯的加倍 .
  • 此处引入一个叫做慢启动的阈值
  • 当拥塞窗口超过这个阈值的时候 , 不再按照指数方式增长 , 而是按照线性方式增长

  • 当TCP开始启动的时候,慢启动阈值等于窗口最大值
  • 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置为1

少量的丢包,我们仅仅是触发超时重传,大量的丢包,我们就认为网络拥塞,当TCP通信开始后,网络吞吐量会逐渐上升,随着网络发生拥堵,吞吐量会立即下降。拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

延迟应答

如果接受数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小.

  • 假设接收端缓冲区为1M.一次收到了500K的数据;如果立刻应答,返回的窗口就是500K
  • 但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了
  • 在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来
  • 如果接收端稍微等一下再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是1M

一定要记得,窗口越大,网络吞吐量就越大,传输效率就越高,我们的目标是在保证网络不拥塞的情况下尽量提高传输效率

那么所有的包都可以延迟应答吗?肯定也不是

  1. 数量限制:每隔N个数据包就应答一次 (一般采取这个)
  2. 时间限制:超过最大延迟时间就应答一次
具体的数量和超时时间 , 依操作系统不同也有差异 ; 一般 N 2, 超时时间取 200ms;

捎带应答 

在延迟应答的基础上 , 我们发现 , 很多情况下 , 客户端服务器在应用层也是 " 一发一收 " . 意味着客户端给服务器说了 "How are you", 服务器也会给客户端回一个 "Fine, thank you";
那么这个时候 ACK 就可以搭顺风车 , 和服务器回应的 "Fine, thank you" 一起回给客户端。

面向字节流

创建一个TCP的socket,同时在内核中创建一个发送缓冲区和一个接受缓冲区

  • 调用write时,数据会先写入发送缓冲区中
  • 如果 发送的字节数 太长,会被拆分成多个TCP的数据包发出
  • 如果发送的字节数太短,就先会在缓冲区里等待,等待缓冲区长度差不多了,或者其他合适的时机发送出去
  • 接受数据的时候,数据也是从网卡驱动程序到达内核的接受缓冲区
  • 然后应用程序可以调用read从接受缓冲区拿数据
  • 另一方面,TCP的一个连接,既有发送缓冲区,也有接受缓冲区,那么对于这一个连接,既可以读数据,也可以写数据,这个概念叫做全双工

由于缓冲区的存在,TCP程序的读和写不需要一一匹配,例如:

  • 写一个100个字节的数据时,可以调用一次write写100个字节,也可以调用100次write,每次写1个字节
  • 读100个字节数据时,也完全不需要考虑写的时候是怎么写的,即可以一次read 100个字节,也可以一次read 一个字节,重复100次。

应用层只管向发送缓冲区拷贝数据,而TCP会按照自己的规则发送数据。写入的时候与写入的格式没有关系。读取的时候与读取的格式毫不相关,因此发送和接受都与格式毫不相关。这就叫做面向字节流。

tcp是面向字节流的,根本不关心任何的数据格式。但是要正确使用这个数据,必须得有特定的格式。这个格式是应用层进行处理的(保证读取到一个完整的报文)

粘包问题

  • 粘包问题中的“包”,是指应用层的数据包
  • 在TCP的协议头中,没有如同UDP一样的“报文长度”这样的字段,但是有一个序号这样的字段
  • 站在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中。
  • 站在应用层的角度,看到的只是一串连续的字节数据
  • 那么应用程序看到了这么一连串的字节数据,就不知道从那个部分开始到哪个部分,是一个完整的应用层数据包

避免粘包问题:明确报文与报文之间的边界

  • 对于定长报文,保证每次都按固定大小读取即可
  • 对于变长的包,可以在报头的位置,约定一个包总长度的字段,从而就知道这个报文的结束位置
  • 对于变长的报还可以在包和包之间使用明确的分隔符(保证分隔符和正文不冲突即可)

UDP是否存在粘包问题?

不存在

  • 对于UDP协议,如果还没有上层交付数据,UDP的报文长度仍然在,同时,UDP是一个一个把数据交付给应用层,就有很明确的数据边界
  • 站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收,不会出现"半个"的情况

TCP异常情况

进程终止:进程终止会释放文件描述符,依然可以发送FIN,和正常关闭没有什么区别

机器重启:和进程终止的情况相同

机器掉电/网线断开:接收端认为链接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset,即使没有写入操作,TCP自己内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放掉。

另外,应用层的某些协议,也有一些这样的检测机制。例如HTTP长连接中会定期检测对方的状态。

用UDP实现可靠传输

udp可以参考tcp可靠性机制,在应用层实现类似的逻辑

例如:

  • 引入序列号,保证数据顺序
  • 引入确认应答,保证对端收到了数据
  • 引入超时重传,如果隔一段时间没有应答,就重发数据。
  • ................

谷歌开发了一个QUIC是基于UDP开发的。文档链接:(英文)RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport (quicwg.org)

QUIC ,即 快速UDP网络连接 ( Quick UDP Internet Connections ), 是由 Google 提出的实验性网络传输协议 ,位于 OSI 模型传输层。 QUIC 旨在解决 TCP 协议的缺陷,并最终替代 TCP 协议, 以减少数据传输,降低连接建立延 迟时间,加快网页传输速度。

 QUIC的特点

  1. 连接建立低时延
  2. 多路复用
  3. 无队头阻塞
  4. 灵活的拥塞控制机制
  5. 连接迁移
  6. 数据包头和包内数据的身份认证和加密
  7. FEC前向纠错
  8. 可靠性传输
  9. 其他

TCP小结

TCP保证可靠性的策略:

  • 校验和
  • 序列号(按序到达)
  • 确认应答
  • 超时重发
  • 连接管理
  • 流量控制
  • 拥塞控制

提高性能的策略:

  • 滑动窗口
  • 快速重传
  • 延迟应答
  • 捎带应答

基于TCP应用层的协议

  • HTTP/HTTPS
  • SSH
  • Telnet

等等

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
本书介绍TCP/IP及其应用。TCP/IP是Internet上使用的协议,而Internet是世界上最大的互联网络。本书内容十分丰富,几乎涵盖了有关TCP/IP的各个方面,包括开放式通信模型、TCP/IP通信模型、IP网络中的命名和寻址机制、地址解析及反向地址解析协议、DNS域字服务器、WINS、地址发现协议、IPv6、IP网络中的路由协议(RIP、OSPF等)、互联网打印协议、LDAP目录服务、远程访问协议、IP安全与防火墙。本书介绍了如何为Windows 9x/NT配置TCP/IP;还介绍了如何使用TCP/IP应用程序,包括远程登录、FTP、Web浏览等。 目 录 译者序 前言 第一部分 TCP/IP基础 第1章 开放式通信模型简介 1 1.1 开放式网络的发展 1 1.1.1 通信处理层次化 2 1.1.2 OSI参考模型 3 1.1.3 模型的使用 5 1.2 TCP/IP参考模型 7 1.3 小结 7 第2章 TCP/IP和Internet 8 2.1 一段历史 8 2.1.1 ARPANET 8 2.1.2 TCP/IP 9 2.1.3 国家科学基金会(NSF) 9 2.1.4 当今的Internet 12 2.2 RFC和标准化过程 12 2.2.1 获得RFC 13 2.2.2 RFC索引 13 2.2.3 有关RFC的幽默 13 2.3 Internet服务简介 13 2.3.1 Whois和Finger 14 2.3.2 文件传输协议 14 2.3.3 Telnet 14 2.3.4 Email 14 2.3.5 WWW 14 2.3.6 USENET News 15 2.4 Intranet和Extranet概览 15 2.4.1 Intranet 15 2.4.2 将Intranet对外开放 16 2.5 Internet的明天 16 2.5.1 下一代Internet(NGI) 16 2.5.2 超速骨干网服务 16 2.5.3 Internet2(I2) 17 2.6 Internet管理组织 17 2.6.1 Internet协会 17 2.6.2 Internet体系结构组 17 2.6.3 Internet工程任务组 17 2.6.4 Internet工程指导组 17 2.6.5 Internet编号管理局 18 2.6.6 Internet名字和编号分配组织 (ICANN) 18 2.6.7 Internet网络信息中心和其他注 册组织 18 2.6.8 RFC编辑 18 2.6.9 Internet服务提供商 18 2.7 小结 19 第3章 TCP/IP概述 20 3.1 TCP/IP的优点 20 3.2 TCP/IP的层和协议 21 3.2.1 体系结构 21 3.2.2 传输控制协议 21 3.2.3 IP协议 23 3.2.4 应用层 25 3.2.5 传输层 25 3.2.6 网络层 25 3.2.7 链路层 25 3.3 远程登录(Telnet) 25 3.4 文件传输协议(FTP) 25 3.5 普通文件传输协议(TFTP) 26 3.6 简单邮件传输协议(SMTP) 26 3.7 网络文件系统(NFS) 26 3.8 简单网络管理协议(SNMP) 27 3.9 TCP/IP和系统结合 27 3.10 内部网概述 28 3.11 小结 28 第二部分 命名和寻址 第4章 IP网络中的名字和地址 29 4.1 IP寻址 29 4.1.1 二进制和十进制数 30 4.1.2 IPv4地址格式 30 4.2 子网的出现 34 4.2.1 分子网 35 4.2.2 可变长子网掩码(VLSM) 37 4.3 无类域前路由(CIDR) 38 4.3.1 无类地址 38 4.3.2 强化路由汇聚 39 4.3.3 超网化 39 4.3.4 CIDR怎样工作 39 4.3.5 公共地址空间 40 4.3.6 RFC 1597和1918 40 4.4 小结 40 第5章 ARP和RARP 41 5.1 使用地址 41 5.1.1 子网寻址 41 5.1.2 IP地址 43 5.2 使用地址解析协议 44 5.2.1 ARP cache 45 5.2.2 代理ARP 47 5.2.3 反向地址解析协议 47 5.3 使用ARP命令 47 5.4 小结 47 第6章 DNS:名字服务器 48 6.1 域名系统概述 48 6.2 授权局 50 6.3 DNS分布数据库 50 6.4 域和区 50 6.5 Internet顶级域 51 6.6 选择一个域名服务器 52 6.7 名字服务解析过程 52 6.7.1 递归查询 52 6.7.2 叠代查询 52 6.8 高速缓存 52 6.9 反向解析(Pointer)查询 52 6.10 DNS安全 52 6.11 资源记录 53 6.12 小结 54 第7章 WINS 55 7.1 NetBIOS 55 7.2 NetBIOS名字解析 57 7.3 动态NetBIOS名字解析 58 7.3.1 使用WINS的优点 58 7.3.2 WINS如何工作 59 7.3.3 配置WINS客户机 60 7.3.4 为代理配置WINS 60 7.3.5 配置NT 4.0系统 61 7.3.6 配置Windows 95或Windows 98 系统 61 7.4 安装WINS服务器 61 7.5 WINS管理和维护 62 7.5.1 加入静态表项 62 7.5.2 维护WINS数据库 63 7.5.3 备份WINS数据库 65 7.5.4 备份WINS注册项 65 7.5.5 恢复WINS数据库 65 7.5.6 压缩WINS数据库 66 7.5.7 WINS复制参与者 66 7.5.8 WINS实现建议 67 7.6 集成WINS和DNS名字解析服务 67 7.7 DHCP服务WINS选项 67 7.8 通过LMHOSTS进行NetBIOS名字 解析 68 7.9 小结 69 第8章 地址发现协议(BOOTP和DHCP) 71 8.1 “引导”协议(BOOTP) 71 8.2 动态主机配置协议(DHCP) 72 8.2.1 DHCP如何工作 72 8.2.2 理解租用地址 73 8.3 管理地址池 74 8.4 DHCP能处理的其他分配 75 8.4.1 注意重载 75 8.4.2 其他分配 75 8.5 小结 76 第三部分 IP和相关协议 第9章 IP协议家族 77 9.1 TCP/IP模型 77 9.1.1 解剖TCP/IP模型 78 9.1.2 协议组件 78 9.2 理解网际协议(IP) 79 9.2.1 IPv4结构 79 9.2.2 IP做什么 80 9.3 理解传输控制协议(TCP) 81 9.3.1 TCP头结构 81 9.3.2 TCP做什么 83 9.4 理解用户数据报协议(UDP) 85 9.4.1 UDP头结构 85 9.4.2 UDP能做什么 85 9.4.3 TCPUDP 86 9.5 小结 86 第10章 IPv6 87 10.1 IPv6数据报 87 10.1.1 优先级分类 88 10.1.2 流标识 89 10.1.3 128位IP地址 89 10.1.4 IP扩展头 90 10.2 多IP地址主机 91 10.3 单播、组播和任一播头 91 10.4 从IPv4到IPv6的过渡 93 10.5 小结 94 第四部分 IP互联 第11章 IP网络中的路由 95 11.1 路由基本知识 95 11.1.1 静态路由 96 11.1.2 距离-向量路由 99 11.1.3 链路-状态路由 100 11.2 IP网络中的收敛 102 11.2.1 适应拓扑变化 102 11.2.2 收敛时间 106 11.3 计算IP网络中的路由 106 11.3.1 存储多条路由 107 11.3.2 初始化更新 107 11.3.3 路由度量标准 107 11.4 小结 108 第12章 路由信息协议(RIP) 109 12.1 理解RFC1058 109 12.1.1 RIP报文格式 109 12.1.2 RIP路由表 111 12.2 操作机制 112 12.2.1 计算距离向量 113 12.2.2 更新路由表 116 12.2.3 寻址问题 118 12.3 拓扑变化 120 12.3.1 收敛 120 12.3.2 计值到无穷 122 12.4 RIP的限制 127 12.4.1 跳数限制 128 12.4.2 固定度量 128 12.4.3 对路由表更新反应强烈 128 12.4.4 收敛慢 128 12.4.5 缺乏负载均衡 128 12.5 小结 129 第13章 开放式最短路径优先 130 13.1 OSPF起源 130 13.2 理解RFC 2328 OSPF,版本2 130 13.2.1 OSPF区 131 13.2.2 路由更新 134 13.3 研究OSPF数据结构 136 13.3.1 HELLO报文 137 13.3.2 数据库描述报文 137 13.3.3 链路-状态请求报文 138 13.3.4 链路-状态更新报文 138 13.3.5 链路-状态应答报文 140 13.4 计算路由 140 13.4.1 使用自动计算 140 13.4.2 使用缺省路由耗费 141 13.4.3 最短路径树 142 13.5 小结 144 第14章 网关协议 145 14.1 网关、桥和路由器 145 14.1.1 网关 145 14.1.2 网桥 146 14.1.3 路由器 146 14.1.4 自治系统 146 14.2 网关协议:基础知识 146 14.3 内部网关协议和外部网关协议 147 14.3.1 网关-网关协议(GGP) 147 14.3.2 外部网关协议(EGP) 147 14.3.3 内部网关协议(IGP) 148 14.4 小结 148 第五部分 网络服务 第15章 互联网打印协议 149 15.1 IPP历史 149 15.2 IPP和端用户 150 15.3 使用HP的IPP实现 151 15.4 小结 152 第16章 LDAP:目录服务 153 16.1 为什么使用目录服务 153 16.2 目录服务的功能 153 16.3 IP上的目录服务 154 16.4 OSI X.500目录模型 156 16.4.1 早期的X.500 157 16.4.2 今天的X.500 157 16.5 LDAP结构 157 16.5.1 LDAP层次结构 157 16.5.2 名字结构 158 16.6 目录系统代理和访问协议 158 16.7 轻型目录访问协议 158 16.7.1 查询信息 159 16.7.2 存储信息 160 16.7.3 访问权限和安全 160 16.8 LDAP服务器-服务器通信 161 16.8.1 LDAP数据互换格式(LDIF) 161 16.8.2 LDAP复制 162 16.9 设计LDAP服务 162 16.9.1 定义需求 162 16.9.2 设计策略 163 16.9.3 性能 164 16.9.4 网络功能 165 16.9.5 安全 166 16.10 LDAP配置 169 16.11 产品环境 169 16.11.1 创建计划 170 16.11.2 有价值的建议 171 16.12 选择LDAP软件 171 16.13 小结 174 第17章 远程访问协议 175 17.1 远程互联 175 17.1.1 ISDN 176 17.1.2 电缆调制解调器 176 17.1.3 数字用户环(DSL) 176 17.1.4 无线网络 177 17.2 远程认证拨入用户服务(RADIUS) 177 17.2.1 RADIUS认证 178 17.2.2 记账信息 179 17.3 用SLIP、CSLIP和PPP传输IP数 据报文 179 17.3.1 串行线路接口协议(SLIP) 179 17.3.2 压缩的SLIP(CSLIP) 180 17.3.3 点到点协议(PPP) 180 17.4 隧道远程访问 184 17.4.1 点到点隧道协议(PPTP) 185 17.4.2 两层隧道协议(L2TP) 188 17.4.3 IPSec 192 17.5 小结 194 第18章 防火墙 195 18.1 使网络安全 195 18.2 使用防火墙 196 18.2.1 代理服务器 197 18.2.2 报文过滤器 198 18.3 使服务安全 198 18.3.1 电子邮件(SMTP) 198 18.3.2 HTTP:万维网 199 18.3.3 FTP 199 18.3.4 Telnet 199 18.3.5 Usenet:NNTP 199 18.3.6 DNS 200 18.4 建造用户自己的防火墙 200 18.5 使用商业防火墙软件 200 18.6 小结 202 第19章 IP安全 203 19.1 使用加密 203 19.1.1 公共-私钥加密 204 19.1.2 对称私钥加密 205 19.1.3 DES、IDEA及其他 205 19.2 数字签名认证 206 19.3 破译加密的数据 207 19.4 保护网络 207 19.4.1 登录名和口令 208 19.4.2 文件的目录允许权限 208 19.4.3 信任关系 209 19.4.4 UNIX和Linux系统上的UUCP 209 19.5 应付最坏情况 210 19.6 小结 210 第六部分 实现TCP/IP 第20章 一般配置问题 211 20.1 安装网卡 211 20.1.1 网卡 211 20.1.2 资源配置 212 20.1.3 安装适配器软件 213 20.1.4 重定向器和API 214 20.1.5 服务 214 20.1.6 NIC接口 215 20.2 网络传输层协议 215 20.2.1 IP配置要求 215 20.2.2 配置缺省网关地址 216 20.2.3 配置名字服务器地址 217 20.2.4 配置邮件服务器地址 217 20.2.5 注册域名 218 20.3 IP配置 218 20.4 配置路由表 218 20.5 异种协议的IP封装 219 20.6 小结 220 第21章 Windows 98 221 21.1 Windows 98网络体系结构 221 21.1.1 安装网卡 222 21.1.2 更改网卡配置 224 21.1.3 当Windows 98引导失败 224 21.2 配置Windows 98的TCP/IP 225 21.2.1 写在开始之前 225 21.2.2 安装TCP/IP 225 21.2.3 配置微软的TCP/IP 225 21.2.4 DNS配置 227 21.2.5 静态配置文件 228 21.2.6 注册表配置 229 21.2.7 测试TCP/IP 231 21.3 小结 232 第22章 Windows 98拨号网络 233 22.1 配置拨号网络适配器 233 22.2 安装拨号网络 234 22.3 服务器类型 235 22.4 编写脚本 238 22.5 多重链接 238 22.6 PPTP 239 22.6.1 安装及配置PPTP 240 22.6.2 建立PPTP连接 240 22.7 Windows 98拨号服务器 241 22.8 解决拨号网络连接中的问题 242 22.8.1 确认DUN配置 242 22.8.2 PPP日志 243 22.9 小结 243 第23章 Windows NT 4.0 244 23.1 Windows NT版本 244 23.2 体系结构 244 23.3 安装Windows NT 4.0 244 23.4 配置TCP/IP 246 23.4.1 IP地址 246 23.4.2 DNS 248 23.4.3 WINS地址 248 23.4.4 DHCP中继 249 23.4.5 路由 250 23.5 简单TCP/IP服务 250 23.6 远程访问服务(RAS) 250 23.7 DHCP服务器 252 23.7.1 安装DHCP服务器服务 252 23.7.2 控制DHCP服务器服务 253 23.7.3 压缩DHCP数据库 253 23.7.4 管理DHCP 254 23.8 使用Microsoft DNS 256 23.8.1 安装DNS 256 23.8.2 创建区 257 23.8.3 配置逆向域名解功能 258 23.8.4 配置DNS与WINS服务器的连 接 259 23.8.5 增加辅助名字服务器 259 23.9 FTP和HTTP服务 259 23.10 TCP/IP打印服务 259 23.10.1 安装TCP/IP打印服务 259 23.10.2 安装LPR服务 260 23.11 Windows 2000新特性 260 23.12 小结 261 第24章 在Novell NetWare中支持IP 262 24.1 Novell与TCP/IP 262 24.1.1 IP与NetWare 4 262 24.1.2 NetWare 5与Pure IP初始化 262 24.2 传统解决方案:NetWare 3.x到 NetWare 4.x的IP支持 263 24.2.1 IP隧道 264 24.2.2 IP中继 264 24.2.3 LAN WorkPlace 264 24.2.4 IPX-IP网关 265 24.2.5 NetWare/IP 265 24.3 NetWare 5—Novell对IP的 完全支持 266 24.3.1 纯IP 266 24.3.2 多协议 266 24.4 安装选项 266 24.4.1 NetWare 5的IP-Only安装 267 24.4.2 IPX-Only安装 267 24.4.3 混合TCP/IP安装 268 24.5 IP迁移辅助工具 268 24.5.1 NDS 268 24.5.2 DNS 269 24.5.3 DHCP 269 24.5.4 DDNS 269 24.5.5 SLP 269 24.5.6 兼容模式 269 24.5.7 迁移代理 270 24.6 迁移策略 270 24.6.1 使用测试平台 270 24.6.2 迁移建议 270 24.7 小结 271 第七部分 使用TCP/IP应用 第25章 Whois和Finger 273 25.1 理解Whois协议 273 25.1.1 互联网注册 273 25.1.2 Whois数据库 274 25.1.3 基于Web的Whois 275 25.1.4 命令行方式的Whois 276 25.1.5 示例 276 25.1.6 基于Telnet的Whois 278 25.2 扩充Whois 279 25.2.1 提示Whois(RWhois) 279 25.2.2 WHOIS++ 280 25.3 使用Finger 280 25.3.1 Finger命令 280 25.3.2 Finger 守护进程 282 25.3.3 非UNIX环境下的Finger 283 25.3.4 Finger的应用 283 25.4 相关RFC文档 285 25.5 小结 285 第26章 文件传输协议 286 26.1 FTP和TFTP在网络世界中的作用 286 26.2 使用FTP传输文件 286 26.2.1 FTP连接 287 26.2.2 使用FTP客户端建立连接 288 26.2.3 FTP安全 296 26.2.4 FTP服务器及守护进程 299 26.2.5 匿名FTP访问 299 26.3 使用TFTP 300 26.3.1 FTP与TFTP的区别 301 26.3.2 TFTP命令 301 26.4 小结 301 第27章 使用Telnet 302 27.1 理解Telnet协议 302 27.2 Telnet守护进程 303 27.3 使用Telnet 304 27.3.1 UNIX telnet命令 304 27.3.2 Telnet GUI应用 305 27.3.3 Telnet命令 305 27.3.4 示例 308 27.4 高级主题 309 27.4.1 安全 309 27.4.2 Telnet应用 309 27.4.3 使用Telnet访问其他TCP/IP 服务 310 27.5 相关RFC文档 312 27.6 小结 313 第28章 使用r系列实用工具 314 28.1 理解r系列命令 314 28.1.1 安全问题 314 28.1.2 禁止使用r系列命令 315 28.1.3 增强r系列命令的安全性 316 28.2 使用r系列命令的替代方法 317 28.3 r系列命令详解 317 28.3.2 相关文件 320 28.4 在非UNIX环境下实现r系 列命令的功能 321 28.5 小结 322 第29章 使用网络文件系统(NFS) 323 29.1 什么是NFS 323 29.1.1 NFS的历史 323 29.1.2 为何使用NFS 323 29.2 实现—NFS工作过程 324 29.2.1 远程过程调用(RPC) 和外部数据表示(XDR) 324 29.2.2 加载类型 324 29.3 NFS使用的文件及命令 325 29.3.1 NFS守护进程 325 29.3.2 与NFS相关的文件 327 29.3.3 NFS服务器命令 329 29.3.4 NFS客户命令 331 29.4 示例:共享及加载NFS文件系统 333 29.5 NFS常见问题及解决方案 334 29.5.1 不能加载 334 29.5.2 不能卸载 334 29.5.3 硬加载与软加载 334 29.6 相关协议及产品 334 29.6.1 WebNFS 335 29.6.2 基于PC的NFS及其他客户端 软件 335 29.6.3 SMB和CIFS 335 29.6.4 其他产品 336 29.7 小结 336 第八部分 使用基于IP的应用 第30章 在应用中集成TCP/IP 337 30.1 使用浏览器作为表示层 338 30.2 不断增加的Internet应用 338 30.3 在已有应用中集成TCP/IP 339 30.4 在其他网络中使用TCP/IP 339 30.4.1 NetBIOS与TCP/IP 339 30.4.2 IPX与UDP 340 30.4.3 ARCNET与TCP/IP 340 30.5 小结 340 第31章 Internet Email协议 341 31.1 电子邮件 341 31.1.1 电子邮件的历史 341 31.1.2 标准及制定标准的组织 341 31.2 X.400 341 31.3 简单邮件传输协议(SMTP) 343 31.3.1 MIME和SMTP 343 31.3.2 其他编码标准 344 31.3.3 SMTP命令 344 31.3.4 SMTP状态码 345 31.3.5 扩展SMTP 345 31.3.6 检查SMTP的头 346 31.3.7 SMTP的优势与不足 347 31.4 使用POP和IMAP取回客户邮件 347 31.4.1 邮局协议(POP) 347 31.4.2 互联网邮件访问协议(IMAP) 348 31.4.3 POP3与IMAP4的比较 348 31.5 高级主题 349 31.6 相关RFC文档及其他参考信息 351 31.7 小结 352 第32章 HTTP: World Wide Web 353 32.1 万维网(WWW) 353 32.1.1 Web简史 353 32.1.2 Web的发展 354 32.2 统一资源定位器 354 32.3 Web服务器与浏览器 355 32.4 理解HTTP 356 32.4.1 HTTP/1.1 356 32.4.2 MIME与Web 358 32.4.3 HTTP通信示例 358 32.5 高级主题 359 32.5.1 服务器方功能 359 32.5.2 SSL和S-HTTP 359 32.6 Web语言 359 32.6.1 HTML 360 32.6.2 XML 360 32.6.3 CGI 361 32.6.4 Java 361 32.6.5 JavaScript 362 32.6.6 动态服务器页面 362 32.7 Web的未来 363 32.7.1 HTTP-ng 363 32.7.2 IIOP 363 32.7.3 IPv6 363 32.7.4 IPP 363 32.8 小结 364 第33章 NNTP:互联网新闻组 365 33.1 互联网新闻组 365 33.2 新闻组和层次 366 33.3 网络新闻传输协议 367 33.3.1 获取新闻组 367 33.3.2 获取消息 369 33.3.3 发布消息 370 33.4 大量广告(Spamming)和新闻黑洞 (Blackholing) 371 33.5 小结 371 第34章 Web服务 373 34.1 Web服务工作概览 373 34.2 主流Web服务器 375 34.3 运行Apache HTTP Web服务 376 34.3.1 下载、安装和配置Apache 376 34.3.2 在Windows环境下使用Apache 381 34.4 浏览其他Web服务器 383 34.5 小结 383 第九部分 使用与管理TCP/IP网络 第35章 协议配置与调整 385 35.1 系统的初始化问题 385 35.2 配置文件 390 35.2.1 在/etc/protocols文件中定义网 络协议 390 35.2.2 在/etc/hosts文件中标识主机 391 35.2.3 TCP/IP与/etc/services文件 392 35.2.4 inetd守护进程与/etc/inetd.conf 文件 394 35.2.5 在/etc/networks文件中设置网络 397 35.2.6 DNS客户与/etc/resolv.conf 397 35.3 小结 398 第36章 配置DNS 399 36.1 域名服务器 399 36.2 资源记录 400 36.3 域名解析 401 36.4 配置UNIX或Linux域名服务器 (DNS) 401 36.4.1 添加资源记录 402 36.4.2 完成DNS文件 402 36.4.3 启动DNS守护进程 405 36.4.4 配置客户端 405 36.5 Windows和域名服务器 405 36.6 小结 406 第37章 网络管理 407 37.1 制定网络监控方案 407 37.2 网络问题及其解决方案 408 37.3 网络管理工具 408 37.3.1 使用协议分析器 409 37.3.2 专家系统 410 37.3.3 基于PC的分析器 410 37.3.4 网络管理协议支持 411 37.3.5 集成网络仿真/模型工具 411 37.4 配置SNMP 412 37.4.1 配置Windows SNMP 413 37.4.2 配置UNIX SNMP 414 37.4.3 SNMP安全属性 414 37.4.4 SNMP代理与管理 415 37.5 SNMP工具及命令 416 37.6 RMON及相关的MIB模型 417 37.7 建立网管需求 417 37.8 小结 419 第38章 SNMP:简单网络管理协议 420 38.1 什么是SNMP 420 38.2 管理信息基(MIB) 421 38.3 使用SNMP 421 38.4 UNIX与SNMP 422 38.4.1 在UNIX和Linux上安装SNMP 423 38.4.2 SNMP命令 424 38.5 Windows与SNMP 424 38.5.1 Windows NT 425 38.5.2 Windows 95、Windows 98和 Windows 3.x 425 38.6 小结 427 第39章 加强TCP/IP传输安全 428 39.1 定义所需的网络安全 428 39.1.1 什么是网络安全 428 39.1.2 为什么网络安全非常重要 429 39.1.3 安全级别 429 39.1.4 口令与口令文件 430 39.1.5 控制对口令的访问 430 39.2 加强网络安全 431 39.2.1 攻击种类 431 39.2.2 加强网络安全 432 39.3 应用配置 434 39.3.1 Internet守护进程与 /etc/inetd.conf 434 39.3.2 网络加密软件 436 39.3.3 TCP Wrapper 436 39.4 使用端口及可信端口 437 39.4.1 防火墙 437 39.4.2 包过滤 437 39.4.3 应用层网关 438 39.4.4 其他应用的过滤 438 39.5 一般安全事务 438 39.5.1 用户帐号维护 438 39.5.2 审计 438 39.5.3 正确的系统配置 438 39.6 小结 438 第40章 问题解决工具及要点 440 40.1 监视网络行为 440 40.2 标准应用程序 440 40.2.1 测试基本连接 441 40.2.2 ping命令 442 40.2.3 解决网络访问故障 443 40.3 解决网络接口层问题 449 40.4 解决网络层问题 449 40.4.1 TCP/IP配置参数 449 40.4.2 IP地址配置问题 450 40.5 解决TCPUDP问题 453 40.6 解决应用层问题 455 40.7 小结 455 第十部分 附 录 附录A RFC及标准化 457 附录B Linux 469 附录C 简写与缩略语 480
TCP/IP 网络编程是指基于TCP/IP协议栈进行网络通信的一种编程方式。TCP/IP协议栈由四层协议组成,包括应用层、TCP/UDP层、IP层和链路层。在TCP/IP网络编程中,程序通过创建套接字(socket)来建立网络连接,使用TCPUDP协议进行数据传输。 TCP/IP的四层协议栈中,应用层负责处理应用程序与网络的交互,包括HTTP、FTP、SMTP等协议;TCP/UDP层负责处理传输层协议,其中TCP提供面向连接的可靠传输,而UDP提供无连接的不可靠传输;IP层负责处理网络层协议,将数据包从源地址传输到目标地址;链路层负责处理物理层协议,将数据转换成比特流进行传输。 在TCP/IP网络编程中,TCP套接字和UDP套接字经过的层级结构有一些差异。TCP套接字在传输层使用TCP协议,提供可靠的、面向连接的数据传输。它通过三次握手的方式建立连接,保证数据的可靠传输。UDP套接字在传输层使用UDP协议,提供无连接的、不可靠的数据传输。它不需要建立连接,直接发送数据包,适用于对传输效率要求较高的场景。 因此,在TCP/IP网络编程中,根据需求选择使用TCP套接字或UDP套接字可以实现不同的传输方式和性能表现。TCP套接字适用于对数据可靠性要求较高的场景,而UDP套接字适用于对传输效率要求较高的场景。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [TCP/IP网络编程(一)](https://blog.csdn.net/m0_45172994/article/details/130534473)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [网络编程——TCP/IP协议](https://blog.csdn.net/m0_49519243/article/details/116132413)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小白又菜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值