计算机网络传输层(超详细!)

举报
幼儿园老大* 发表于 2024/07/04 12:44:30 2024/07/04
【摘要】 传输层功能将应用层的报文封装到传输层中,使用 TCP 或者 UDP 协议建立两个主机进程之间的端对端通信,传输层会自动对上层数据进行分用和复用:不同的应用层报文可封装到同一个传输层报文中传输,到达后再拆分报文交付给应用层中的各个进程。通信双方根据套接字(IP 地址 + 端口号)相互识别。UDP 协议UDP 提供不可靠但高效的、无连接的服务:在传送数据之前不需要建立连接,远地主机在收到 UDP...

传输层功能

将应用层的报文封装到传输层中,使用 TCP 或者 UDP 协议建立两个主机进程之间的端对端通信,

传输层会自动对上层数据进行分用和复用:不同的应用层报文可封装到同一个传输层报文中传输,到达后再拆分报文交付给应用层中的各个进程。通信双方根据套接字(IP 地址 + 端口号)相互识别。


UDP 协议

UDP 提供不可靠但高效的、无连接的服务

  1. 在传送数据之前不需要建立连接,远地主机在收到 UDP 报文后也不需要给出任何确认(只检测报文检验和,出现错误直接丢弃)。

  2. 一般用于即时通信,如语音、视频、直播等场景。


TCP 协议

TCP 提供可靠的、面向连接的服务

  1. 在传送数据之前必须先建立连接,数据传送结束后要释放连接。传输过程中会校验数据并返回确认,保证可靠性。

  2. 一般用于文件传输、发送和接收邮件、远程登录等场景。

TCP 连接

建立连接

建立 TCP 协议采用了三次握手策略:SYN 是 TCP/IP 建立连接时使用的握手信号,接收者到后以 ACK 信号响应(序号加一)。

  1. 客户端向服务端 发送带有 SYN 标志的数据包(客户端请求连接)
  2. 服务端向客户端 发送带有 SYN/ACK 标志的数据包(客户端可以正常发送消息)
  3. 客户端向服务端 发送带有带有 ACK 标志的数据包(服务端可以正常发送消息,连接建立)

断开连接

断开 TCP 连接采用了四次挥手策略:FIN 是 TCP/IP 断开连接时使用的终止信号,接收者到后以 ACK 信号响应(序号加一)。

  1. 客户端向服务端 发送带有 FIN 标志的数据包(客户端请求终止)
  2. 服务器向客户端 发送带有 ACK 标志的数据包(客户端不再发送消息,连接半关闭)
  3. 服务器向客户端 发送带有 FIN 标志的数据包(服务端请求终止)
  4. 客户端向服务端 发送带有 ACK 标志的数据包(服务端不再发送消息,连接关闭)

TCP 可靠传输

编号和校验和

  • 编号

发送方将应用报文分割成 TCP 报文段后,会为每一个报文段进行编号。由接收方对数据包进行排序,再把有序数据传送给应用层。

如果收到重复报文段,直接丢弃。

  • 校验和

发送方会计算 TCP 报文段全部数据的检验和,并保存在报文段首部。由接收方对数据包数据进行检验。

如果收到错误报文段,丢弃报文段,并返回错误消息等待重发。

IP 协议校验和只校验首部, TCP 协议校验全部数据。

ARQ 协议

(自动重传请求)发送方发送报文段后,会等待接收方 ACK。如果接收到错误消息或等待超时,将重发这个报文段。用来实现可靠传输。

现在一般使用连续 ARQ 协议:维持一个发送窗口,可以连续发送出去多个报文段而不需要等待对方确认。接收方对按序到达的最后一个报文段发送确认,即表明之前的所有报文段都已经正确收到。提高信道利用率。

如果发送方连续发送了 5 条消息,其中 3 号消息丢失。接收方只会对前两个消息发送确认。发送方必须对后三条消息全部重传。

流量控制和阻塞控制

  • 流量控制:减少数据发送,防止接收方过载导致数据无法处理。

  • 拥塞控制: 减少数据发送,防止网络阻塞导致数据无法到达。

发送方允许连续发送的分组上限受以上两个因素制约,即 发送窗口 = min (接收窗口, 阻塞窗口)

  1. 接收窗口大小由 接收方返回的确认报文中的窗口字段设定。

  2. 拥塞窗口大小根据网络的拥塞程度动态变化,TCP 拥塞窗口变化采取了慢开始、拥塞避免、快重传 和 快恢复 四种策略。


TCP通信

Socket类

Socket在建立网络连接时使用。连接成功时应用程序两端都会产生一个Socket实例指向对方,完成所需的会话。

服务器端

  1. 创建ServerSocket对象,绑定监听端口监听客户端请求。
  2. 接收客户端请求,创建Socket与该客户建立专线连接(多线程)。
  3. 双方通过输入输出流进行对话。
  4. 关闭流和套接字,继续等待新的连接。

客户端

  1. 创建Socket对象,指明需要连接的服务器地址和端口号。
  2. 连接建立后,通过输出流向服务器发送请求信息。
  3. 双方通过输入输出流进行对话。
  4. 关闭流和套接字。

创建Socket对象

ServerSocket server = new ServerSocket(55533);

创建ServerSocket对象,并指定服务器端接口

Socket socket = new Socket(127.0.0.1, 55533);

创建Socket对象,并指明对方主机和接口

监听端口

Socket socket = server.accept();

ServerSocket接收请求,并且返回一个客户端的Socket对象实例。

Accept方法用于产生“阻塞”(由循环产生),使程序运行停在这个地方,直到一个会话产生。

进行对话


//打开输出流
OutputStream out = socket.getOutputStream();
//输出信息(字节流)
String message = "Hello";
out.write(message.getBytes("UTF-8"));
out.write("end");
//关闭输出流
out.close();Copy to clipboardErrorCopied

输出流输出信息,另一端输入流将得到输入。失败则抛出IOException



//打开输入流(转化为字节流被缓冲流读取)
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
//输入信息(接收到end字符则结束)
StringBuilder message = new StringBuilder();
while ((str = in.readLine()) != null && "end".equals(str)) {
  message.append(str);
}
System.out.println("get message: " + message);
//关闭输入流
in.close(); //socket.shutdownOutput();Copy to clipboardErrorCopied

输入流输入信息,得到另一端输出流信息。失败则抛出IOException

//客户端

public class SocketClient {
  public static void main(String args[]) throws Exception {
    //与本地服务器端建立连接
    String host = "127.0.0.1"; 
    int port = 55533;
    Socket socket = new Socket(host, port);

    //控制台输入并向服务器端输出
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));      
    BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));         
    while (str != "end") {
      String str = bufferedReader.readLine();
      bufferedWriter.write(str + "\n");
      bufferedWriter.flush();
    }

    //关闭连接
    outputStream.close();
    socket.close();
  }
}Copy to clipboardErrorCopied
//服务器端

public class SocketServer {
  public static void main(String[] args) throws Exception {
    // 监听指定的端口
    int port = 55533;
    ServerSocket server = new ServerSocket(port);

    //循环等待请求
    while(true){
      //建立连接
      Socket socket = server.accept();
      //从socket中获取输入流并读取
      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
      String str;,
      while ((str = bufferedReader.readLine()) != null) {
        System.out.println("get message from client:" + str);
      }
      //关闭连接
      inputStream.close();
      socket.close();
    }
  }
}Copy to clipboardErrorCopied

1> 多线程

每有一个Socket请求的时候,就创建一个线程来处理它。(通常交给线程池管理,保证线程的复用)

能够循环处理多个Socket请求,否则一个请求的处理耗时,后面的请求将被阻塞。

//服务器端(线程池管理)

public class SocketServer {
    public static void main(String[] args) throws IOException {
        // 监听指定的端口
        int port = 55533;
        ServerSocket server = new ServerSocket(port);
        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        //循环等待请求
        while (true) {
            //建立连接
            Socket socket = serverSocket.accept();
            //分配线程
            Runnable runnable = () -> {
                BufferedReader bufferedReader = null;
                //从socket中获取输入流并读取
                try {
                    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                    String str;
                    while ((str = bufferedReader.readLine()) != null) {
                        System.out.println("get message from client:" + str);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            };
            executorService.submit(runnable);
        }
    }
}Copy to clipboardErrorCopied

2> 规范流输入输出长度

在实际应用中,socket发送的数据并不是按行发送。我们就不会每次发送数据,都用“\n”标识区分是否发送完毕。

在实际应用中,我们通过是采用数据长度+类型+数据的方式来告知一次流输入完成,方便进行后续操作。

https://blog.csdn.net/qq_33865313/article/details/79363640

https://www.cnblogs.com/huanzi-qch/p/9889521.html

Socket的消息推送机制中,用的都是 Ajax 轮询。在特定的时间间隔由客户端自动发出请求,将服务器的消息主动拉回来(服务器启动一个线程去监听与此客户端的通信),这种方式是非常消耗资源的,因为它本质还是http请求,而且显得非常笨拙:服务端不能主动向客户端推送数据。

####WebSocket类

import javax.websocket.*;

WebSocket 在浏览器和服务器完成一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。多客户端、涉及有界面的聊天建议使用websocket(嵌入到了浏览器的内核中)。

https://www.cnblogs.com/interdrp/p/7903736.html

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。