• Java之TCP和UDP进行网络编程


    目录

    一.网络编程

    1.1网络编程的作用

    1.2网络编程的基本概念   

    1.3网络编程的实现

    二.UDP网络编程

    2.1UDP数据报套的初步了解

    2.2Java数据报套接字通信模型 

    2.3Java编程实现UDP通信

    三.TCP网络编程

     3.1TCP流套接字api

    3.2TCP通信代码实现

    3.2.1短连接实现代码

    3.2.2长连接实现代码

    四.总结


    🎁个人主页tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主
    🎥 本文由 tq02 原创,首发于 CSDN🙉
    🎄 本章讲解内容:TCP和UDP的编程讲解

    🎥学习专栏:  C语言         JavaSE       MySQL基础     多线程学习

    一.网络编程

    1.1网络编程的作用

    网络编程:指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)

    换句话说:通过网络编程可以进行网络资源的数据传输,例如:腾讯视频观看网络电视

    1.2网络编程的基本概念   

    在一次网络数据传输时:

            发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。

            接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。

            收发端:发送端和接收端两端,也简称为收发端。

    注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念

    网络数据传输的请求和响应

    一般而言,获取一个网络资源需要涉及到两次的网络数据传输:

    1. 请求数据的发送   -----客户端
    2. 响应数据的发送   ------服务端

    注:客户端将资源保存在服务端,例如设置密码,将密码保存在服务端,这样即使换台客户端也能登陆。

    1.3网络编程的实现

            网络编程的实现是通过Socket套接字,由系统供用于网络通信的技术,将传输层协议划主要划分为两类:TCP协议和UDP协议。因此TCP和UDP是网络资源数据传输的重要协议

    重点:牢记Socket套接字。TCP和UDP都有其api,通过这个可以进行网络编程。

    二.UDP网络编程

    2.1UDP数据报套的初步了解

            在Java当中,实现UDP协议的通信的类是-----DatagramSocket(Socket对象),DatagramPacket(udp数据报)

    • DatagramPacket(udp数据报):将需要的传输数据写入其中,传输后也需要该类接收数据。
    • DatagramSocket(Socket对象):发送和接收udp数据报。

    2.2Java数据报套接字通信模型 

             java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用

    DatagramPacket 作为发送或接收的 UDP 数据报。对于一次发送及接收 UDP 数据报的流程如下:

    1. 发送端:使用DatagramPacket类构造发送的内容,由DatagramSocket发送出去。
    2. 接收端:使用DatagramPacket类保存接收的数据,由DatagramSocket接收该类。

    注:在实际情况下,服务器需要提供多个客户端的请求处理及响应。

    流程图如下:


    2.3Java编程实现UDP通信

            在编程之前,我们先要了解两个类---- DatagramPacket和DatagramSocket。

    注:服务器相当于家,客户端相当于你,当你想回家时,我们需要得到服务器的地址(IP地址),门牌号(端口号)

    (1)DatagramPacket

    构造方法

    构造方法方法说明
    DatagramPacket(byte[]
    buf, int length)
    接收数据报 ,接收的数据保存在字节数组(第一个参数buf )中,接收指定长度
    (第二个参数length)
    DatagramPacket(byte[]
    buf, int offset, int length,
    SocketAddress address)
    发送数据报 ,发送的数据为字节 数组(第一个参数buf )中,从 0 到指定长度
    (第二个参数 length)。 address 指定目的主机的 IP 和端口号

    方法:

    方法名方法说明
    InetAddress
    getAddress()
    从接收的数据报中,获取发送端主机 IP 地址;或从发送的数据报中,获取接收端主机IP 地址
    int getPort()
    从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
    byte[] getData()
    获取数据报中的数据

    (2)DatagramSocket

    构造方法:

    构造方法方法说明
    DatagramSocket()
    创建一个 UDP 数据报套接字的 Socket ,绑定到本机任意一个随机端口
    (一般用于客户端)
    DatagramSocket(int
    port)
    创建一个 UDP 数据报套接字的 Socket ,绑定到本机指定的端口(一般用
    于服务端)
    方法:
    方法解析
    void receive(DatagramPacket p)
    从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
    void send(DatagramPacketp)
    从此套接字发送数据报包(不会阻塞等待,直接发送)
    void close()
    关闭此数据报套接字

    我们这以自己的地址为例子,环回IP。

    客户端代码:

    1. package network;
    2. import java.io.IOException;
    3. import java.net.*;
    4. import java.util.Scanner;
    5. public class UdpEchoClient {
    6. private DatagramSocket socket = null;
    7. private String serverIp;
    8. private int serverPort;
    9. // 服务器的 ip 和 服务器的端口.
    10. public UdpEchoClient(String ip, int port) throws SocketException {
    11. serverIp = ip;
    12. serverPort = port;
    13. // 这个 new 操作, 就不再指定端口了. 让系统自动分配一个空闲端口.
    14. socket = new DatagramSocket();
    15. }
    16. // 让这个客户端反复的从控制台读取用户输入的内容. 把这个内容构造成 UDP 请求, 发给服务器. 再读取服务器返回的 UDP 响应
    17. // 最终再显示在客户端的屏幕上.
    18. public void start() throws IOException {
    19. Scanner scanner = new Scanner(System.in);
    20. System.out.println("客户端启动!");
    21. while (true) {
    22. // 1. 从控制台读取用户输入的内容
    23. System.out.print("-> "); // 命令提示符, 提示用户要输入字符串.
    24. String request = scanner.next();
    25. // 2. 构造请求对象, 并发给服务器.
    26. DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
    27. InetAddress.getByName(serverIp), serverPort);
    28. socket.send(requestPacket);
    29. // 3. 读取服务器的响应, 并解析出响应内容.
    30. DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
    31. socket.receive(responsePacket);
    32. String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
    33. // 4. 显示到屏幕上.
    34. System.out.println(response);
    35. }
    36. }
    37. public static void main(String[] args) throws IOException {
    38. //服务器ip与端口
    39. UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
    40. client.start();
    41. }
    42. }

    服务器代码:

    1. package network;
    2. import java.io.IOException;
    3. import java.net.DatagramPacket;
    4. import java.net.DatagramSocket;
    5. import java.net.SocketException;
    6. // UDP 的 回显服务器.
    7. // 客户端发的请求是啥, 服务器返回的响应就是啥.
    8. public class UdpEchoServer {
    9. private DatagramSocket socket = null;
    10. // 参数是服务器要绑定的端口
    11. public UdpEchoServer(int port) throws SocketException {
    12. socket = new DatagramSocket(port);
    13. }
    14. // 使用这个方法启动服务器.
    15. public void start() throws IOException {
    16. System.out.println("服务器启动!");
    17. while (true) {
    18. // 反复的, 长期的执行针对客户端请求处理的逻辑.
    19. // 一个服务器, 运行过程中, 要做的事情, 主要是三个核心环节.
    20. // 1. 读取请求, 并解析
    21. DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
    22. socket.receive(requestPacket);
    23. // 这样的转字符串的前提是, 后续客户端发的数据就是一个文本的字符串.
    24. String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
    25. // 2. 根据请求, 计算出响应
    26. String response = process(request);
    27. // 3. 把响应写回给客户端
    28. // 此时需要告知网卡, 要发的内容是啥, 要发给谁.
    29. DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
    30. requestPacket.getSocketAddress());
    31. socket.send(responsePacket);
    32. // 记录日志, 方便观察程序执行效果.
    33. System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(), requestPacket.getPort(),
    34. request, response);
    35. }
    36. }
    37. // 根据请求计算响应. 由于是回显程序, 响应内容和请求完全一样.
    38. public String process(String request) {
    39. return request;
    40. }
    41. public static void main(String[] args) throws IOException {
    42. UdpEchoServer server = new UdpEchoServer(9090);
    43. server.start();
    44. }
    45. }

    三.TCP网络编程

     3.1TCP流套接字api

            如果想实现TCP的通信,我们需要使用到ServerSocket和Socket。

    注意:TCP传输数据,是根据流操作,因此我们需要使用IO流操作

    (一)ServerSocket

    • ServerSocket:创建TCP服务端的Socket的API,服务器端通常用于监听指定的端口并等待客户端的连接请求

            构造方法:

    构造方法方法说明
    ServerSocket(int port)
    创建一个服务端流套接字 Socket ,并绑定到指定端口

            方法:

    方法方法说明
    Socket  accept()
    监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端 Socket 对象,并基于该Socket 建立与客户端的连接,否则阻塞等待
    close()
    关闭此套接字

    (二)Socket

    • Scoket:用于客户端,服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket

    注:socket通常是一个对网络通信进行抽象的对象,通过它可以实现客户端和服务器之间的数据传输。

    构造方法:

    构造方法方法说明
    Socket(String host, int port)
    创建一个客户端流套接字 Socket ,并与对应 IP 的主机上,对应端口的进程建立连接

    方法:

    方法名方法说明
    InetAddress getInetAddress()
    返回套接字所连接的地址
    InputStream getInputStream()
    返回此套接字的输入流
    OutputStream getOutputStream()
    返回此套接字的输出流

    3.2TCP通信代码实现

            TCP代码实现通信,需要先建立连接,而确认什么时候关闭,却可以分为2种----短连接和长连接!
    1. 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
    2. 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

    长、短连接区别:

    1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要 第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时 的,长连接效率更高。
    2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
    3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于 客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

    3.2.1短连接实现代码

            短连接,则是一发一收,客户端发送请求,服务器接收请求,只有请求,没有回应。

    服务端:

    1. package org.example.tcp.demo1;
    2. import java.io.*;
    3. import java.net.ServerSocket;
    4. import java.net.Socket;
    5. public class TcpServer {
    6.    //服务器socket要绑定固定的端口
    7.    private static final int PORT = 8888;
    8.    public static void main(String[] args) throws IOException {
    9.        // 1.创建一个服务端ServerSocket,用于收发TCP报文
    10.        ServerSocket server = new ServerSocket(PORT);
    11.        // 不停的等待客户端连接
    12.        while(true) {
    13.            System.out.println("---------------------------------");
    14.            System.out.println("等待客户端建立TCP连接...");
    15.            // 2.等待客户端连接,注意该方法为阻塞方法
    16.            Socket client = server.accept();
    17.            System.out.printf("客户端IP:%s%n", client.getInetAddress().getHostAddress());
    18.            System.out.printf("客户端端口号:%s%n", client.getPort());
    19.            // 5.接收客户端的数据,需要从客户端Socket中的输入流获取
    20.            System.out.println("接收到客户端请求:");
    21.            InputStream is = client.getInputStream();
    22.            // 为了方便获取字符串内容,可以将以上字节流包装为字符流
    23.            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
    24.            String line;
    25.            // 一直读取到流结束:TCP是基于流的数据传输,一定要客户端关闭Socket输出流才表示服
    26. 务端接收IO输入流结束
    27.            while ((line = br.readLine()) != null) {
    28.                System.out.println(line);
    29.           }
    30.            // 6.双方关闭连接:服务端是关闭客户端socket连接
    31.            client.close();
    32.       }
    33.   }
    34. }

    客户端

    1. package org.example.tcp.demo1;
    2. import java.io.*;
    3. import java.net.Socket;
    4. public class TcpClient {
    5.    //服务端IP或域名
    6.    private static final String SERVER_HOST = "localhost";
    7.    //服务端Socket进程的端口号
    8.    private static final int SERVER_PORT = 8888;
    9.    public static void main(String[] args) throws IOException {
    10.        // 3.创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接
    11.        Socket client = new Socket(SERVER_HOST, SERVER_PORT);
    12.        // 4.发送TCP数据,是通过socket中的输出流进行发送
    13.        OutputStream os = client.getOutputStream();
    14.        // 为了方便输出字符串作为发送的内容,可以将以上字节流包装为字符流
    15.        PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
    16.        // 4-1.发送数据:
    17.        pw.println("hello world!");
    18.        // 4-2.有缓冲区的IO操作,真正传输数据,需要刷新缓冲区
    19.        pw.flush();
    20.        // 7.双方关闭连接:客户端关闭socket连接
    21.        client.close();
    22.   }
    23. }

    以上便是短连接,客户端不会收到回应。

    3.2.2长连接实现代码

            客户端发送请求,服务器接收请求,然后将其分析对其作出回应,传回客户端。

    服务端:

    1. import java.io.*;
    2. import java.net.*;
    3. public class TCPServer {
    4. public static void main(String[] args) throws IOException {
    5. System.out.println("服务器已启动");
    6. // 创建ServerSocket对象,监听指定端口
    7. ServerSocket serverSocket = new ServerSocket(8888);
    8. while (true) {
    9. // 等待客户端连接
    10. Socket socket = serverSocket.accept();
    11. System.out.println("已连接客户端:" + socket.getInetAddress() + ":" + socket.getPort());
    12. // 接收客户端消息
    13. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    14. String readLine = null;
    15. while ((readLine = br.readLine()) != null) {
    16. System.out.println("客户端消息:" + readLine);
    17. // 回复客户端消息
    18. PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
    19. pw.println("Server reply: " + readLine);
    20. }
    21. }
    22. }
    23. }

    客户端:

    1. import java.io.*;
    2. import java.net.*;
    3. public class TCPClient {
    4. public static void main(String[] args) throws IOException {
    5. // 创建Socket对象,连接指定IP和端口
    6. Socket socket = new Socket("localhost", 8888);
    7. // 发送消息给服务器
    8. PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
    9. pw.println("Hello server, I am a client.");
    10. // 接收服务器消息
    11. BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    12. String readLine = null;
    13. while ((readLine = br.readLine()) != null) {
    14. System.out.println("服务器消息:" + readLine);
    15. }
    16. // 关闭资源
    17. br.close();
    18. pw.close();
    19. socket.close();
    20. }
    21. }

    四.总结

            其实,TCP的编程比UDP要难一点点,但是只要我们理解了UDP的编程实现,我们可以更方便理解TCP的编程知识。

            TCP的通信代码实现,需要操作流操作,我们需要理解充分!

       在学习本文之前,如果你有时间,我希望你可以查看一下:网络的发展史、通信基础和原理

                                                                                                    TCP和UDP的由浅到深的详细讲解

  • 相关阅读:
    亿级万物互联新时代的物联网消息中间件EMQX调研
    Android 12.0 mt6771新增分区功能实现二
    如何找到能商用的背景纯音乐
    定时保存正在编辑的文档原理阐述及通过windowsApi实现
    Java的日期类常用方法
    vue3 + vue-router + keep-alive缓存页面
    渠道管控,为什么最好找第三方
    openGauss学习笔记-73 openGauss 数据库管理-创建和管理索引
    Pulsar bundle数目的选择
    每天五分钟计算机视觉:基于KNN算法完成图片分类任务
  • 原文地址:https://blog.csdn.net/m0_74097410/article/details/133649237