• Java Socket网络编程


    一.Socket概述

    Java网络编程主要涉及的内容是Socket编程。

    ​ Socket(套接字),是网络上两个程序之间实现数据交换的一端,它既可以发送请求,也可以接受请求,一个Socket由一个IP地址和一个端口号唯一确定,利用Socket能比较方便的实现两端(服务端和客户端)的网络通信。

    ​ 在Java中,有专门的Socket类来处理用户请求和响应,学习使用Socket类方法,就可以实现两台机器之间通信。

    Socket通信是有两种方式的:TCP和UDP。

    ​ TCP通信:客户端提供了java.net.Socket类,服务器端提供了java.net.ServerSocket类。

    ​ UDP通信:UDP通信不建立逻辑连接,使用DatagramPacket类打包数据包,使用DatagramSocket类发送数据包。

    Socket通信模型如下图:

    在这里插入图片描述

    二. TCP通信客户端Socket

    ​ Java中专门用来实现Socket客户端的类就叫Socket,这个类实现了客户端套接字,用于向服务器发出连接请求等。

    • 构造方法:

      Socket(String host, int port):创建一个流套接字并将其连接到指定IP地址的指定端口号。

      如果host为null,则相当于指定地址为回送地址。

      回送地址(来自百度百科):

      ​ 127.x.x.x是本机的会送地址,即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回之,不进行任何网络传输。

    • 主要方法:

      • InputStream getInputStream():返回此套接字的输入流。

        关闭生成的InputStream也将关闭相关的Socket。

      • OutputStream getOutputStream():返回此套接字的输出流。

        关闭生成的OutputStream也将关闭相关的Socket。

      • void close():关闭此套接字

    三. TCP通信服务器端ServerSocket

    ​ Java中专门用来建立Socket服务器的类叫ServerSocket,这个类实现了服务器套接字,该对象等待通过网络的请求。

    • 构造方法:

      ServerSocket(int port):创建绑定到特定端口的服务器套接字。

    • 主要方法:

      • Socket accept():监听并接受连接,返回一个新的Socket对象,用于和客户端通信,该方法会一直阻塞直到建立连接。

      • void close():关闭此套接字。

    四.基于TCP的Socket通信

    1. 步骤分析:

      • 服务端先启动,创建ServerSocket对象,等待连接。
      • 客户端启动,创建Socket对象,请求连接。
      • 服务器端接收请求,调用accept方法,并返回一个Socket对象。
      • 客户端的Socket对象获取OutputStream,向服务器端发送数据。
      • 服务器端Socket对象获取InputStream,读取客户端的数据。
      • 服务器端Socket对象获取OutputStream,向客户端发送数据。
      • 客户端的Socket对象获取InputStream,读取服务器的数据。
      • 客户端释放资源,断开连接。
    2. 主要代码

      • 服务器端

        import java.io.*;
        import java.net.ServerSocket;
        import java.net.Socket;
        
        
        public class TCPServer {
            public static void main(String[] args) throws IOException {
                System.out.println("Server start...");
                ServerSocket server = new ServerSocket(1234);
                
                while (true) {
                    Socket client = server.accept();
        
                    // 字节流转为字符流
                    InputStreamReader isr = new InputStreamReader(client.getInputStream());
                    // 字符流转换为缓冲流
                    BufferedReader br = new BufferedReader(isr);
        
                    // 读取
                    String line = null;
                    while ((line = br.readLine()) != null) {
                        System.out.println("接收到客户端信息:" + line);
                    }
        
                    // 发送信息到客户端 字节流转字符流
                    OutputStreamWriter out = new OutputStreamWriter(client.getOutputStream());
                    // 字符流转换为缓冲流
                    BufferedWriter bw = new BufferedWriter(out);
                    
                    String str = "你好,服务器收到了";
                    bw.write(str);
                    bw.flush();
        
                    // 关闭资源
                    client.close();
                }
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
      • 客户端

        import java.io.*;
        import java.net.Socket;
        
        public class TCPClient {
            public static void main(String[] args) throws IOException {
                System.out.println("Client start...");
                Socket client = new Socket("localhost", 1234);
        
                OutputStreamWriter osw = new OutputStreamWriter(client.getOutputStream());
                BufferedWriter bw = new BufferedWriter(osw);
        
                String str = "你好,我是客户端";
                bw.write(str);
                bw.flush();
        
                // 发送一个终结符,告诉服务器,已经发送完毕
                client.shutdownOutput();
        
                InputStreamReader isr = new InputStreamReader(client.getInputStream());
                BufferedReader br = new BufferedReader(isr);
        
                String line = null;
        
                while((line = br.readLine()) != null) {
                    System.out.println("接收到服务器消息:" + line);
                }
        
                // 释放资源
                client.close();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31

        注意:

        ​ 在交互时,服务器accept是阻塞的,read也是阻塞的,所以在发送完数据后,需要调用shutdownOutput来告知发送结束,否则会一直阻塞。

    五.UDP相关类DatagramPacket类和DatagramSocket类

    1. 数据包类DatagramPacket
      • 作用:用来封装发送端或接收端要发送或接收的数据。
      • 构造方法
        • DatagramPacket(byte[] buf, int length):构造DatagramPacket,用来接收长度为length的数据包。
        • DatagramPacket(byte[] buf, int length, InetAddress address, int port):构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号。
      • 常用方法
        • public int getLength():获得发送端实际发送的字节数或接收端世界接收的字节数
        • public int getPort():获得发送端或接收端端口号
    2. 发送数据包类DatagramSocket
      • 作用:用来发送和接收数据包对象
      • 构造方法
        • DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
        • DatagramSocket(int port):创建数据包套接字并将其绑定到本地主机上指定端口。
      • 常用方法
        • public void send(DatagramPacket p):从此套接字发送数据报包
        • public void receive(DatagramPacket p):从此套接字接收数据报包
        • public void close():关闭此数据报套接字
    3. InetAddress类(无构造方法)
      • 作用:代表一个IP地址
      • 静态方法
        • public static InetAddress getLocalHost():返回本地主机
        • public static InetAddress getByName():在给定主机名的情况下确定主机的 IP 地址。
      • 普通方法
        • public String getHostName(): 获取此 IP 地址的主机名。
        • public String getHostAddress():返回 IP 地址字符串(以文本表现形式)

    六.基于UDP的Socket通信

    1. 步骤分析

      • 服务器端先启动,创建DatagramSocket对象,监听端口,用于接收
      • 服务器端创建DatagramPacket对象,打包用于接收的数据包
      • 服务器阻塞等待接收
      • 客户端启动,创建DatagramSocket对象,监听端口,用于接收
      • 客户端创建DatagramPacket对象,打包用于发送的数据包
      • 客户端发送数据,服务端接收
      • 服务端接收数据后,创建DatagramPacket对象,打包用于发送的数据包,发送数据
      • 客户端创建DatagramPacket对象,打包用于接收的数据包,阻塞等待接收
      • 客户端接收服务端数据,断开连接,释放资源
    2. 主要代码

      • 服务器

        import java.io.IOException;
        import java.net.*;
        
        public class UDPServer {
            public static void main(String[] args) throws IOException {
                System.out.println("Server Start...");
        
                // 保存接收的数据
                byte[] rData = new byte[1024];
        
                // 接收时监听端口8888
                DatagramSocket ds = new DatagramSocket(8888);
                DatagramPacket rdp = new DatagramPacket(rData, rData.length);
        
                while (true) {
                    ds.receive(rdp);
                    System.out.println("Receive:" + new String(rData));
        
                    // 发送数据
                    byte[] sData = "你好,我是服务器".getBytes();
                    DatagramPacket sdp = new DatagramPacket(sData, sData.length, rdp.getAddress(), rdp.getPort());
            
                    ds.send(sdp);
                }
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
      • 客户端

        import java.io.IOException;
        import java.net.*;
        
        public class UDPClient {
            public static void main(String[] args) throws IOException {
                System.out.println("Client login...");
                // 构建数据包
                byte[] sendData = "Hello,I am Client".getBytes();
                InetAddress sendAddress = InetAddress.getLocalHost();
                DatagramPacket dp = new DatagramPacket(sendData, sendData.length, sendAddress, 8888);
                DatagramSocket ds = new DatagramSocket(1234);
                ds.send(dp);
        
                // 创建数据包,接收数据
                byte[] receiveData = new byte[1024];
                DatagramPacket rdp = new DatagramPacket(receiveData, receiveData.length);
                ds.receive(rdp);
        
                System.out.println("Receive:" + new String(receiveData));
        
                ds.close();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23

      注意:

      UDP通信双方,对应端口号一致才可以,比如发送方使用1234端口,接收方需要监听1234端口才可以。

  • 相关阅读:
    [CF643F]Bears and Juice
    09 【Attributes继承 provide与inject】
    kafka
    68.C++纯虚函数与抽象类
    Bigemap如何查看历史影像
    Unity地面交互效果——4、制作地面凹陷轨迹
    数据结构--5.2马踏棋盘算法(骑士周游问题)
    Go语言并发编程——原子操作
    【YOLOV5-5.x 源码讲解】整体项目文件导航
    Android系统源码目录详解
  • 原文地址:https://blog.csdn.net/chisuisi5702/article/details/126284676