计算机网络(TCP协议)

一、概念

  • 网络之间通过路由器连接,这就构成一个覆盖范围更大的计算机网络,这就称之为互联网
    在这里插入图片描述
  • 网络把许多计算机连接在一起。
    互联网网络通过路由器连接在一起。
    与网络相连的计算机称之为主机(通过IP地址标识),网络互连并不是把计算机简单地在物理层面连接起来,因为这样计算机不能够进行交互,所以我们还必须在计算机上安装能够交互的软件(port端口)才行。
    在这里插入图片描述

计算机网络的分类

  1. 按照网络的作用范围分类
    1)广域网(WAN):长距离运送数据
    2)域域网(MAN):一个城市或跨越街区城市
    3)局域网(LAN)
    4)个人区域网(PAN):个人电子设备,使用无线技术连接起来的网络(例:手机热点)
  2. 按照网络的使用者分类
    1)公有网
    2)私有网

计算机网络中性能指标

  1. 速率:数据传输速率
  2. 带宽:表示网络中某通道传输数据的能力,单位时间内网络信道所能通过的最高
  3. 吞吐量:单位时间内某个网络实际的数据量
  4. 时延
    1)发送时延
    2)传播时延
    3)处理时延
    4)排队时延
  5. 往返时间 RTP

网络体系结构

计算机网络各层协议的集合就是网络的体系结构,下面是几种常用协议:
在这里插入图片描述

  1. OSI 七层协议体系结构
    各层协议数据单元:
OSI七层协议数据单元
7 应用层报文
6 表示层
5 会话层
4 传输层报文段 / 用户数据报
3 网络层数据报
2 数据链路层
1 物理层比特
  1. TCP/IP 体系结构(4层
    应用层 传输层 网际层(网络层) 网络接口层
  2. 五层协议 的体系结构
    应用层 传输层 网络层 数据链路层 物理层
    1)应用层
    应用进程之间的交互,这里的进程指的是在主机中正在运行的程序。应用层交互的数据单元称为报文
    2)运输层
    向两台主机中进程之间的通信提供一个数据传输服务。
    运输层起着承上启下的作用,涉及源端节点到目的端节点之间可靠信息的传输。传输层需要解决网络连接的建立和释放(涉及TCP协议/UDP协议)
    3)网络层
    网络层负责分组交换网上的不同主机提供通信扶额u,在发送数据时,网络层会将传输层产生的报文端或用户的数据报封装成分组或者包进行传输。网络层传输的是数据报
    4)数据链路层
    两台主机之间的数据传输,总是在链路上传输,所以需要链路层。链路层传输的数据称之为
    5)物理层
    物理层所传输的单位是比特,发送方发送01,接收方接收0或1。
  • 数据在往下一层传输时,需要加上下一层数据单元所需要的控制信息。
  • 最常用的体系结构:TCP/IP 体系结构,TCP/IP 体系结构

五层协议举例:

  • 主机1 往 主机2发送数据。(实际上是指主机1的应用程序往主机2的应用程序发送数据)
  • 主要过程如下图:
    在这里插入图片描述

二、TCP协议 / UPD协议

TCP协议

  1. 概念
    TCP协议是数据传输控制协议,是面向连接的传输层协议,采用字节流机制传输数据。
  2. 特点
    (1)提供可靠交付服务,通过TCP连接传输的数据,无差错、不丢失、不重复;
    (2)提供全双工通信
    (3)面向字节流,点对点通信
  3. 网络通信 两要素
    主机 IP
    端口 port

TCP编程

在实现TCP编程之前,首先要了解Java Socket

  • socket称之为“套接字”,用于描述IP地址和端口号,是一个通信的句柄。应用程序通过套接字向网络中发送请求或者应答请求(客户端 <-> 服务器端)
    客户端 Socket
    服务器端 ServerSocket
    这两者都存在于java.net

客户端(Socket常用于API)

  • Accept常用于产生“阻塞”,直到接收一个连接,并且返回一个客户端的Socket对象实例。服务器端使用,如果该方法有返回值,说明此时有一个客户端请求当前服务器端,接下来的操作都需要使用这样的一个返回值。
  • 简单来说:客户端有连接,accpet()返回一个Socket;客户端没有连接,就一直处于阻塞状态。
    getInputStream 获取网络连接输入
    getOutStream 获取网络连接的输出

服务器端

  • 实现服务器端需要构造ServerSocket,下面是会用到的方法
    ServerSocket()
    ServerSocket(int port)
    ServerSocket(int port,int backlog)
    ServerSocket(int port,int backlog,InetAddress bindAddr)

服务器端如何应对多个客户端访问

  1. backlog 一个线程处理多个请求(backlog参数用来设置连接请求队列的长度)
  2. 多线程
    实现逻辑(下图):
    在这里插入图片描述
    TCP编程流程图:
    在这里插入图片描述

服务器端代码实现:

//子线程                                                                                       
class SocketHandler extends Thread{                                                         
    private Socket socket;                                                                  
    public SocketHandler(Socket socket){                                                    
        this.socket = socket;                                                               
    }                                                                                       
                                                                                            
    @Override                                                                               
    public void run() {                                                                     
        BufferedReader reader = null;                                                       
        OutputStream outputStream = null;                                                   
        //进行通信                                                                              
        try {                                                                               
            while (true) {                                                                  
                //进行读操作                                                                     
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String msg = reader.readLine();                                             
                System.out.println("客户端:"+socket.getRemoteSocketAddress()+"发送信息:"+msg);     
                //进行写操作                                                                     
                outputStream = socket.getOutputStream();                                    
                outputStream.write(("reponse:"+msg+"\n").getBytes());                       
                if("".equals(msg) || "exit".equals(msg)){                                   
                    System.out.println("lvting-Debug");                                     
                    break;                                                                  
                }                                                                           
            }                                                                               
        } catch (IOException e) {                                                           
            e.printStackTrace();                                                            
        }finally {                                                                          
            try {                                                                           
                reader.close();                                                             
                outputStream.close();                                                       
            } catch (IOException e) {                                                       
                e.printStackTrace();                                                        
            }                                                                               
        }                                                                                   
    }                                                                                       
} 
//主线程                                                                                          
public class MyTcpServer {                                                                  
    public static void main(String[] args) throws IOException {                             
        ServerSocket serverSocket = null;                                                   
        try {                                                                               
            serverSocket = new ServerSocket(3333);                                          
            System.out.println("服务器端已经启动...");                                              
            while (true){                                                                   
                //进行监听等待客户端连接                                                               
                Socket accept = serverSocket.accept();                                      
                System.out.println("与客户端:"+accept.getRemoteSocketAddress()+"连接建立成功...");    
                //将accept实例交给子线程处理客户端请求                                                     
                new SocketHandler(accept).start();                                          
            }                                                                               
                                                                                            
        } catch (Exception e) {                                                             
            e.printStackTrace();                                                            
        }finally {                                                                          
            serverSocket.close();                                                           
        }                                                                                   
    }                                                                                       
}                                                                                                                                                                                      

客户端代码:

public class MyTcpClient {                                                                  
    public static void main(String[] args) {                                                
        Socket socket = null;                                                               
        BufferedReader input = null;                                                        
        BufferedReader reader = null;                                                       
        PrintWriter output = null;                                                          
        try {                                                                               
            //构造Socket                                                                      
            socket = new Socket("127.0.0.1", 3333);                                         
            System.out.println("客户端已经启动...");                                               
            while (true){                                                                   
                //发送数据到服务器端                                                                 
                //获取控制台的输入流                                                                 
                input = new BufferedReader(new InputStreamReader(System.in));               
                String info = input.readLine();                                             
                //获取连接对象的输出流                                                                
                output = new PrintWriter(socket.getOutputStream());                         
                System.out.println("debug-info:"+info);                                     
                //输出流对象写入info数据                                                             
                output.println(info);//tcp存在缓冲区,有可能缓冲区没有刷新就导致数据无法传输                         
                output.flush();                                                             
                //输出服务器端返回的数据                                                               
                //获取连接对象的输入流                                                                
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String strs = reader.readLine();                                            
                System.out.println("客户端显示--服务器端响应的数据:"+strs);                               
            }                                                                               
        } catch (Exception e) {                                                             
            e.printStackTrace();                                                            
        }finally {                                                                          
            try {                                                                           
                socket.close();                                                             
                reader.close();                                                             
                input.close();                                                              
                output.close();                                                             
            } catch (Exception e) {                                                         
                e.printStackTrace();                                                        
            }                                                                               
        }                                                                                   
    }                                                                                       
}                                                                                           

在这里插入图片描述

  • TCP协议是传输层向上面的应用层提供通信服务的协议。提供面向连接的服务,再传输数据之前必须要建立连接,数据传输之后还需要释放连接,TCP产生的额外开销会比较大
    保证可靠传输(安全):确认机制、流量控制、拥塞控制机制等也需要占用处理器资源。

TCP建立连接的过程(三次握手)

  • 为了准确无误地将数据送达目标处, TCP 协议采用了三次握手(three-way handshaking) 策略。 用 TCP 协议把数据包送出去后, TCP不会对传送后的情况置之不理, 它一定会向对方确认是否成功送达
  • 握手过程中使用了 TCP 的标志(flag) —— SYN(synchronize) 和 ACK(acknowledgement) 。
    发送端首先发送一个带 SYN 标志的数据包给对方。
    接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。
    ③ 最后, 发送端再回传一个带 ACK 标志的数据包, 代表“握手”结束。
  • 若在握手过程中某个阶段莫名中断, TCP 协议会再次以相同的顺序发送相同的数据包
  1. 第一次握手
    client发送连接请求数据报文到server端。client进入SYN_SENT状态;
  2. 第二次握手
    server收到连接请求数据报文,如果同意建立连接,向client回应确认报文段(为TCP连接分配TCP缓存和变量);
  3. client收到server确认之后,它再次向服务器端发送确认数据报文段;(第三次握手)
    在这里插入图片描述seq表示当前传输的字节流第一个字节的编号
    下面是更容易理解的版本:
    在这里插入图片描述
  • 三次握手可不可以设置为两次?
    不行。如果发送端第一次发送的连接请求1没有及时到达,收不到接收端的回复,它就会再次发送一个 连接请求2,接收端回复后成功连接。进行通信后断开连接。此时 连接请求1(超时)到达,接收端就会再次处理了这个过期请求,因此不可以设置为两次。

TCP断开连接的过程(四次挥手)

  1. 第一次挥手
    client发送一个断开连接的请求数据报文到server
  2. 第二次挥手
    server收到断开连接请求数据报文之后,只是回应一个确认报文段
  3. 第三次挥手
    server发送一个关闭连接请求数据报文到client
    当前TCP的报文段存活时间为2MSL,等待2MSL为了保证最后一个报文段都能够到达。
  4. 第四次挥手
    client发回ACK数据报文确认
    在这里插入图片描述
    等待2MSL再进行最后一次挥手,保证最后一个报文段都能从server发送到client。(报文段存活最长时间为2MSL)
  • 四次挥手可不可以设置为三次?
    不可以。如果只有三次挥手,意味着客户端发送了请求报文之后,server将断开连接的请求和ack的请求同时发送给client(没有第二次)。client端回复ACK完成三次挥手。但此时server端发送缓冲区或网络节点上还有未发送完的数据,会造成数据的丢失

UDP协议

特点:

  1. UDP是无连接状态
  2. UDP尽最大能力交付
  3. UDP面向报文
  4. UDP协议没有拥塞控制
  5. UDP头部开销小
    只有4个字段:源端口 目的端口 长度 校验和

UDP编程逻辑:编程时只需要将数据进行打包
服务器端:

try {
            //构造发送数据的对象
            DatagramSocket socket = new DatagramSocket(6666);
            //接收数据
            byte[] buf = new byte[1024];
            //将数据接收
            DatagramPacket dp = new DatagramPacket(buf, 1024);
            socket.receive(dp);
            String info = new String(dp.getData(), 0, dp.getLength());
            System.out.println("接收到数据为: "+info);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

客户端:

//将数据进行打包
        String info = "hello world";
        try {
            //构造发送数据的对象
            DatagramSocket socket = new DatagramSocket();
            //将数据打包-> 发送
            DatagramPacket dp = new DatagramPacket(info.getBytes(), info.length(), InetAddress.getByName("localhost"), 6666);
            socket.send(dp);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

TCP和UDP的区别?

  • TCP
    面向连接可靠的流式服务
    流式服务:数据是一个数据流,数据没有界限,数据的发送和接收存在直接的联系;
    面向连接,可靠:
    ① 应答确认机制 & 超时重传机制
    ② 保证有序,每一个TCP数据报文都会有序号
    ③ 接收的数据和源数据完全相同,数据没有损坏
  • UDP
    无连接不可靠的面向报文的服务。
    尽最大努力交付,即不保证可靠交付。
    实时性强工作效率高,适用于对高速传输和实时性有较高的通信或广播通信。

表格对比:

TCPUDP
面向连接无连接
可靠不可靠
面向字节流面向报文
点对点通信点对点一对一一对多多对多通信
首部开销 20字节首部开销 8字节
对系统资源要求较对系统资源要求较
传输效率低传输效率高
传输速度慢传输速度快

TCP为什么可靠?

  1. 确认和重传机制
    建立连接时三次握手同步双方的“序列号 + 确认号 + 窗口大小信息”,是确认重传、流控的基础。传输过程中,如果Checksum校验失败、丢包或延时,发送端重传。
  2. 数据排序
    TCP有专门的序列号SN字段,可提供数据re-order
  3. 流量控制
    滑动窗口和计时器的使用。TCP窗口中会指明双方能够发送接收的最大数据量,发送方通过维持一个发送滑动窗口来确保不会发生由于发送方报文发送太快接收方无法及时处理的问题。
  4. 拥塞控制(由4个核心算法组成):
    “慢启动”(Slow Start)
    “拥塞避免”(Congestion avoidance)
    “快速重传 ”(Fast Retransmit)
    “快速恢复”(Fast Recovery)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值