TCP、UDP协议的应用、ServerSocket和Socket、DatagramSocket和DatagramPacket

DAY13.1 Java核心基础

TCP协议

TCP 协议是面向连接的运算层协议,比较复杂,应用程序在使用TCP协议之前必须建立连接,才能传输数据,数据传输完毕之后需要释放连接

就好比现实生活中的打电话,首先确保电话打通了才能进行通信,如果没有打通则阻塞,需要等待打通才能对话

TCP优缺点:

  • 优点:安全可靠,数据不会丢失,并且数据是按照先后顺序依次到达
  • 缺点:速度慢,效率低,常用于对于业务安全要求较高的场景

Java中如何使用 TCP 呢?

java中通过Socket类来建立TCP连接,使用这个类可以在服务端和客户端建立一个可靠的连接

Socket表示客户端,ServerSocket表示服务端

它们都在java.net包中

在服务端创建ServerSocket对象,通过对象的accept()方法可以接收到若干个表示客户端的Socket对象

ServerSocket

方法 描述
public ServerSocket(int port) 根据端口创建 ServerSocket 实例对象
public ServerSocket(int port,int backlog) 根据端口和 backlog 创建 ServerSocket 对象
public ServerSocket(int port,int backlog,InetAddress address) 根据端口、backlog、IP 创建 ServerSocket对象
public ServerSocket() 创建没有绑定服务器的 ServerSocket 对象
public synchronized int getSoTimeout() 获取 Sotimeout 的设置
public InetAddress getInetAddress() 获取服务器的 IP 地址
public Socket accept() 等待客户端请求,并返回 Socket 对象
public void close() 关闭 ServerSocket
public boolean isClosed() 返回 ServerSocket 的关闭状态
public void bind(SocketAddress address) 将 ServerSocket 实例对象绑定到指定地址
public int getLocalPort() 返回 ServerSocket 的端口

Socket

方法 描述
public Socket(String host,int port) 根据主机、端口创建 Socket 对象
public Socket(InetAddress host,int port) 根据 IP、端口创建 Socket 对象
public Socket(String host,int port,InetAddress address,int localPort) 根据主机、端口创建要连接的 Socket 对象并将其连接到指定的远程主机上的指定端口
public Socket(InetAddress host,int port,InetAddress address,int localPort) 根据主机、端口创建要连接的 Socket 对象并将其连接到指定的远程主机上的指定端口
pubilc Socket() 创建没有连接的 Socket 对象
public InputStream getInputStream() 返回 Socket 的输入流
public synchronized void close() 关闭 Socket
public boolean isClosed() 返回 Socket 的关闭状态、

DataInputStream 的作用

读取基本数据类型:提供方法直接读取二进制数据为Java基本类型,例如:

  • int readInt():读取4字节为int。
  • double readDouble():读取8字节为double。
  • String readUTF():读取修改后的UTF-8编码字符串。

跨平台一致性:数据以**网络字节序(Big-Endian)**存储,确保不同平台间数据读写兼容。

DataOutputStream 的作用

写入基本数据类型:将Java基本类型转换为字节序列写入流中,例如:

  • void writeInt(int v):将int写入为4字节。
  • void writeDouble(double v):将double写入为8字节。
  • void writeUTF(String str):以修改后的UTF-8格式写入字符串。

数据序列化:常用于将数据结构(如对象的字段)转换为字节流,便于存储或网络传输。

服务端启动的时候可以接收多个客户端的信息

服务端:ServerSocket

java 复制代码
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        DataInputStream dataInputStream = null;
        DataOutputStream dataOutputStream = null;
        try {
            serverSocket = new ServerSocket(8080);
            System.out.println("------服务端------");
            System.out.println("已启动,等待接收客户端请求...");
            while (true){
                socket = serverSocket.accept();
                inputStream = socket.getInputStream();
                dataInputStream = new DataInputStream(inputStream);
                String request = dataInputStream.readUTF();
                System.out.println("接收到了客户端请求:" + request);
                outputStream = socket.getOutputStream();
                dataOutputStream = new DataOutputStream(outputStream);
                String response = "Hello World";
                dataOutputStream.writeUTF(response);
                System.out.println("给客户端做出响应:" + response);
            }
        } catch (Exception e){

        } finally {
            try {
                dataOutputStream.close();
                outputStream.close();
                dataInputStream.close();
                inputStream.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

核心就是通过while循环accept()接收客户端的连接,然后通过DataInputStream和DataOutputStream实现了接收和发送的业务

启动等待客户端连接...

客户端:Socket

java 复制代码
public class Client {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        DataOutputStream dataOutputStream = null;
        InputStream inputStream = null;
        DataInputStream dataInputStream = null;
        try {
            socket = new Socket("127.0.0.1", 8080);
            System.out.println("------客户端------");
            String request = "你好!";
            System.out.println("客户端说:" + request);
            outputStream = socket.getOutputStream();
            dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF(request);
            inputStream = socket.getInputStream();
            dataInputStream = new DataInputStream(inputStream);
            String response = dataInputStream.readUTF();
            System.out.println("服务器的响应是:" + response);
        } catch (Exception e){

        } finally {
            try {
                inputStream.close();
                dataInputStream.close();
                dataOutputStream.close();
                outputStream.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端接收到的消息:

此时服务端的输出为:

UDP协议

TCP 协议连接可以建立稳定可靠的连接,保证信息的完整性,但是它的缺点也很明显,先建立连接再进行操作的方式效率必然低下

实际开发应用中,有些场景不需要可靠的连接,而是需要效率很高的传输,但连接不可靠,容易数据丢失

TCP:打电话,需要建立连接

UDP(发送消息,不需要建立连接):

  • 效率高,速度快,不需要建立连接,直接发送即可
  • 连接不可靠,容易数据丢失,安全性不高

DatagramSocket和DatagramPacket

DatagramSocket (邮箱,等待接收消息):

方法 描述
public DatagramSocket(int port) 根据端口创建 DatagramSocket 实例对象
public void send(DatagramPacket p) 发送数据报
public synchronized void receive(DatagramPacket p) 接收数据报
public InetAddress getInetAddress() 获取 DatagramSocket 对应的 InetAddress 对象
public boolean isConnected() 判断是否连接到服务

DatagramPacket(信封:封装发送的消息以及发送的地址):

方法 描述
public DatagramPacket(byte[] buff,int length,InetAddress address,int port) 根据发送的数据、数据长度、IP、端口创建 DatagramPacket 对象
public synchronized byte[] getData() 获取接收的数据
public synchronized int getLength() 获取数据长度
public synchronized int getPort() 获取发送数据的 Socket 端口
public synchronized SocketAddress getSocketAddress() 获取发送数据的 Socket 信息

客户端A:

java 复制代码
public class TerminalA {
    public static void main(String[] args) {
        // 创建信箱
        try {
            byte[] buff= new byte[1024];
            SocketAddress socketAddress =new InetSocketAddress("127.0.0.1",8081);
            DatagramPacket datagramPacket= new DatagramPacket(buff,buff.length,socketAddress);
            DatagramSocket datagramSocket =new DatagramSocket(8080);
            // 等待接收8081信箱的消息
            System.out.println("客户端A等待接收消息....");
            datagramSocket.receive(datagramPacket);
            // 接收消息
            String msg = new String(datagramPacket.getData(),0,datagramPacket.getLength());
            System.out.println("接收到来自"+datagramPacket.getAddress()+":"+datagramPacket.getPort()+"端口的消息:"+msg);
            // 发送消息
            String s = "你好我是客户端A";
            byte[] bytes = s.getBytes();
            DatagramPacket datagramPacket1 =new DatagramPacket(bytes,bytes.length,new InetSocketAddress("127.0.0.1",8081));
            datagramSocket.send(datagramPacket1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

如果没有消息则一直阻塞等待

阻塞发生在 datagramSocket.receive(datagramPacket);

客户端 B:

java 复制代码
public class TerminalB {
    public static void main(String[] args) {
        try {
            // 创建信箱
            DatagramSocket datagramSocket =new DatagramSocket(8081);
            // 发送消息给8080
            String s = "你好我是客户端B";
            byte[] bytes = s.getBytes();
            DatagramPacket datagramPacket1 =new DatagramPacket(bytes,bytes.length,new InetSocketAddress("127.0.0.1",8080));
            datagramSocket.send(datagramPacket1);

            // 接收消息
            SocketAddress socketAddress =new InetSocketAddress("127.0.0.1",8080);
            byte[] buff= new byte[1024];
            DatagramPacket datagramPacket= new DatagramPacket(buff,buff.length,socketAddress);
            // 等待接收8080信箱的消息
            System.out.println("客户端B等待接收消息....");
            datagramSocket.receive(datagramPacket);
            String msg = new String(datagramPacket.getData(),0,datagramPacket.getLength());
            System.out.println("接收到来自"+datagramPacket.getAddress()+":"+datagramPacket.getPort()+"端口的消息:"+msg);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

发送消息给A,A给B回信

相关推荐
无职转生真好看3 小时前
TCP怎么保证可靠传输
服务器·网络·tcp/ip
开开心心就好9 小时前
功能强大的电脑硬件检测及驱动安装工具
android·python·网络协议·tcp/ip·macos·django·pdf
百锦再10 小时前
《C#上位机开发从门外到门内》3-4:基于TCP/IP的远程监控系统设计与实现
网络·网络协议·tcp/ip·udp·c#·上位机·通信
23级二本计科16 小时前
TCP 全连接队列 内核层理解socket
服务器·网络·tcp/ip
好好学习O(∩_∩)O17 小时前
[网络][tcp协议]:tcp报头
服务器·网络·tcp/ip
stackY、21 小时前
【Linux】:socket编程——UDP
linux·运维·服务器·udp
开开心心就好1 天前
攻克 PDF 发票打印难题,提升财务效率
android·python·网络协议·tcp/ip·macos·pdf·tornado
白嫖一茶1 天前
TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)
网络·网络协议·tcp/ip
玩转4G物联网1 天前
玩转物联网-4G模块如何快速将数据上传到巴法云(TCP篇)
物联网·网络协议·tcp/ip·iot·核心板·fs800dtu·巴法云