079.JAVA网络编程_TCP和UDP协议


博主的 Github 地址


1. 传输层协议

  • 传输层中有两个协议: TCP 和 UDP

1.1. TCP

1.1.1. TCP 协议的概述
  • 传输控制协议 TCP(Transmission Control Protocol) 协议,
    是一种面向连接的, 可靠的, 基于字节流的传输层通信协议.
    • 面向连接, 传输可靠(保证数据正确性, 保证数据顺序)
    • 用于传输大量数据(流模式)
    • 速度慢, 建立连接需要开销较多(时间, 系统资源)
1.1.2. TCP 的传输特点
  • 通过面向连接, 端到端和可靠的数据包发送.

    • TCP 为了保证报文传输的可靠, 就给每个包一个序号,
      同时序号也保证了传送到接收端实体的包的按序接收.
      • 若接收端实体对已成功收到的字节发回一个相应的确认(ACK);
      • 若发送端实体在合理的往返时延(RTT)内未收到确认, 对应的数据将会被重传.
  • 分为服务端和客户端

1.1.3. TCP 建立连接的过程
  • TCP 是因特网中的传输层协议, 使用三次握手协议建立连接.

  • 当主动方发出 SYN 连接请求后, 等待对方回答 SYN + ACK ,
    并最终对对方的 SYN 执行 ACK 确认.

  • 这种建立连接的方法可以防止产生错误的连接,
    TCP 使用的流量控制协议是可变大小的滑动窗口协议.

  • TCP 建立连接的过程如下:

    • 客户端发送 SYN(SEQ=x) 报文给服务器端, 进入 SYN_SEND 状态.

    • 服务器端收到 SYN 报文, 回应一个 SYN(SEQ=y)ACK(ACK=x+1) 报文,
      进入 SYN_RECV 状态.

    • 客户端收到服务器端的 SYN 报文, 回应一个 ACK(ACK=y+1) 报文,
      进入 Established 状态.

    • 三次握手完成, TCP 客户端和服务器端成功地建立连接, 可以开始传输数据了. pic

  • TCP 断开连接的过程如下:
    建立一个连接需要三次握手, 而终止一个连接要经过四次握手,
    这是由 TCP 的半关闭(half-close)造成的.

    • 某个应用进程首先调用 close, 称该端执行"主动关闭"(active close) 该端的 TCP 于是发送一个 FIN 分节, 表示数据发送完毕.

    • 接收到这个 FIN 的对端执行"被动关闭"(passive close),
      这个 FIN 由 TCP 确认.

    • 注意:
      FIN 的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,
      放在已排队等候该应用进程接收的任何其他数据之后, 因为, FIN 的接收意味着
      接收端应用进程在相应连接上再无额外数据可接收.

    • 一段时间后, 接收到这个文件结束符的应用进程将调用 close 关闭它的套接字.
      这导致它的 TCP 也发送一个 FIN.

    • 接收这个最终 FIN 的原发送端 TCP(即执行主动关闭的那一端)确认这个 FIN.
      整个过程每个方向都需要一个 FIN 和一个 ACK, 因此通常需要 4 个分节. pic


1.2. UDP

  • 用户数据报协议 UDP(User Datagram protocol) 一种无连接的传输层协议,
    提供面向事务的简单不可靠信息传送服务.

  • 面向非连接, 传输不可靠(可能丢包/数据丢失),
    用于传输少量数据(数据包模式), 速度快.

  • 分为发送端和接收端


2. TCP 操作实例

  • 涉及到两个类, 分别对应服务端和客户端
  • 因此需要分别写出服务端和客户端的程序
  • 这两个类为:
    • java.net.Socket 此类实现客户端套接字
    • java.net.ServerSocket 此类实现服务器套接字

2.1. TCP 程序实例

2.1.1. 创建服务端程序
public class Server{
  public static void main(String[] args) throws Exception{
    //创建服务端对象, 指定端口为8888
    ServerSocket server = new ServerSocket(8888);

    //接收连接服务端的客户端对象
    Socket client = server.accept();

    //定义服务端返回数据, 并传递给客户端
    Sting alert = "Connect Success";

    //获取客户端对象的输出流对象, 表明将服务端数据传送给客户端
    OutputStream os = client.getOutputStream();

    //用打印流包装客户端输出流, 让数据直接输出到客户端程序中
    PrintStream ps = new PrintStream(os);
    ps.println(alert);

    //关闭打印流和服务器
    ps.close();
    server.close();
  }
}
2.1.2. 创建客户端程序
public class Server{
  public static void main(String[] args) throws Exception{
    //创建客户端对象, 指定连接服务器IP为127.0.0.1, 指定端口为8888
    Socket client = new Socket("127.0.0.1", 8888);

    //客户端获取从服务器中输入的数据, 调用客户端对象的输入流即可获取
    //同时用扫描器类进行封装
    Scanner sc = new Scanner(client.getInputStream);

    //在客户端的控制台进行输出
    while(sc.hasNextLine()){
      String line = sc.nextLine();
      System.out.println(line);
    }

    //关闭输入流和客户端对象
    sc.close();
    client.close();
  }
}
2.1.3. 备注
  • 若服务端程序要一直接受客户端对象, 则需要用死循环去执行程序.

3. UDP 操作实例

  • 涉及两个类, 分别用来接受/发送数据和封装数据成数据包

    • java.net.DatagramSocket 此类表示用来发送和接收数据报包的套接字.
    • java.net.DatagramPacket 此类表示数据报包
  • 程序也要分开为发送端和接收端来进行编写.


3.1. UDP 程序实例

3.1.1. 发送端
public class Sender{
  public static void main(String[] args) throws Exception{
      //创建发送端对象, 指定发送端口为10010
      DatagramSocket sender = new DatagramSocket(10010);

      //定义发送的数据
      String data = "this is the data";

      //封装要发送的数据
      DatagramPacket dp = new DatagramPacket(
              data.getBytes(), //发送的数据转换成byte数组
              data.getBytes().length, //发送的数据的字节长度
              "127.0.0.1", //发送的目标地址的IP
              10086 //发送的目标地址所开放的端口号
              );

      //发送数据
      sender.send(dp);

      //关闭发送对象
      sender.close();
  }
}
3.1.2. 接收端
public class Receiver{
  public static void main(String[] args) throws Exception{
      //创建接收端对象, 指定接收端口为10086
      DatagramSocket receiver = new DatagramSocket(10086);

      //先定义一个缓冲区用以接受数据
      byte[] b = new byte[1024];

      //接收端对象利用缓冲区来接受数据, 并存入一个数据包中
      DatagramPacket dp = new DatagramPacket(b, 1024);
      receiver.receive(dp);

      //获取接受的数据并转化成字符串
      String msg = new String(dp.getData(), 0, dp.getLength());

      //在接收端后台输出接受的数据
      System.out.println(msg);

      //关闭接收端对象
      receiver.close();
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值