当前位置: 首页 > article >正文

04_网络编程

网络编程

什么是网络编程

可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)

java.net.* 包下提供了网络编程的解决方案

通信的基本架构
  • CS 架构(Client 客户端 / Server 服务端)
  • BS 架构(Browser 客户端 / Server 服务端)
网络通信三要素
  • IP 地址
  • 端口号
  • 协议
IP 地址
import java.net.InetAddress;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 获取本机IP地址对象
        InetAddress ip1 = InetAddress.getLocalHost();
        System.out.println(ip1.getHostName());  // TOMATO
        System.out.println(ip1.getHostAddress());  // 10.233.86.87

        // 2. 获取指定IP或者域名的IP地址对象
        InetAddress ip2 =  InetAddress.getByName("www.baidu.com");
        System.out.println(ip2.getHostName());  // www.baidu.com
        System.out.println(ip2.getHostAddress());  // 120.232.145.185

        // 3. 判断6000毫秒内,是否能够连通百度
        System.out.println(ip2.isReachable(6000));  // true
    }
}
端口号
  • 标记正在计算机设备上运行的应用程序,被规定为一个16位的二进制,范围是 0 ~ 65535
通信协议
  • 网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议
  • UDP(User Datagram Protocol):用户数据报协议;
  • TCP(Transmission Control Protocol):传输控制协议

UDP

  • 特点:无连接,不可靠通信
快速入门
// 客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建客户端对象
        DatagramSocket socket = new DatagramSocket();

        // 2. 创建数据包对象封装要发出去的数据
        /*
        public DatagramPacket(byte buf[], int length, SocketAddress address) {
            参数一 : 封装要发出去的数据
            参数二 : 发送出去的数据大小(字节个数)
            参数三 : 服务端的IP地址(找到服务端主机)
            参数四 : 服务端的端口
        }
        */
        byte[] bytes = "我是客户端".getBytes();
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
                InetAddress.getLocalHost(), 6666);

        // 3. 开始正式发送这个数据包的数据出来了
        socket.send(packet);
        System.out.println("客户端数据发送完毕!");

        // 4. 关闭连接,释放其所占用的网卡资源
        socket.close();
    }
}
// 服务端

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动---");
        // 1. 创建一个服务端对象
        DatagramSocket socket = new DatagramSocket(6666);  // 参数:端口号

        // 2. 创建一个数据包对象,用于接收数据
        byte[] buffer = new byte[1024 * 64];  // 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);  // 参数:

        // 3. 正式使用数据包来接收客户端发来的数据
        socket.receive(packet);

        // 客户端ip
        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(packet.getPort());

        // 4. 从字节数组中,把接收到的数据直接打印出来
        // 接收多少就倒出多少
        // 获取本次数据包接收了多少数据
        int len = packet.getLength();
        String res = new String(buffer, 0, len);
        System.out.println(res);
    }
}
多发多收
// 客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建客户端对象
        DatagramSocket socket = new DatagramSocket();

        // 2. 创建数据包对象封装要发出去的数据
        /*
        public DatagramPacket(byte buf[], int length, SocketAddress address) {
            参数一 : 封装要发出去的数据
            参数二 : 发送出去的数据大小(字节个数)
            参数三 : 服务端的IP地址(找到服务端主机)
            参数四 : 服务端的端口
        }
        */
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入>>> ");
            String msg = sc.nextLine();
            // 如果用户输入exit命令,就执行退出
            if ("exit".equals(msg)) {
                System.out.println("欢迎再来!");
                socket.close();  // 4. 关闭连接,释放其所占用的网卡资源
                break;
            }

            byte[] bytes = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
                    InetAddress.getLocalHost(), 6666);

            // 3. 开始正式发送这个数据包的数据出来了
            socket.send(packet);
            System.out.println("客户端数据发送完毕!");
        }
    }
}
// 服务端

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动---");
        // 1. 创建一个服务端对象
        DatagramSocket socket = new DatagramSocket(6666);  // 参数:端口号

        // 2. 创建一个数据包对象,用于接收数据
        byte[] buffer = new byte[1024 * 64];  // 64KB
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);  // 参数:

        while (true) {
            // 3. 正式使用数据包来接收客户端发来的数据
            socket.receive(packet);

            // 客户端ip
            System.out.println(packet.getAddress().getHostAddress());
            System.out.println(packet.getPort());

            // 4. 从字节数组中,把接收到的数据直接打印出来
            // 接收多少就倒出多少
            // 获取本次数据包接收了多少数据
            int len = packet.getLength();
            String res = new String(buffer, 0, len);
            System.out.println(res);
            System.out.println("-------------------");
        }
    }
}

TCP

  • 特点:面向连接,可靠通信
快速入门
// 客户端

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务器程序的连接
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2. 从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os =  socket.getOutputStream();

        // 3. 把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        // 4. 开始写数据出去了
        dos.writeUTF("我们还是好朋友,对吧?");
        dos.close();  // 关闭数据输出流管道

        socket.close();  // 释放连接资源
    }
}
// 服务端

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动---");

        // 1. 创建 ServerSocket 的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2. 使用 serverSocket 对象,调用一个 accept 方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();

        // 3. 从 socket 通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();

        // 4. 把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        // 5. 使用数据输入流读取客户端发送过来的消息
        String res = dis.readUTF();
        System.out.println(res);

        // 输出客户端的IP地址
        System.out.println(socket.getRemoteSocketAddress());

        dis.close();
        socket.close();
    }
}
多发多收
// 客户端

package login;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务器程序的连接
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2. 从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();

        // 3. 把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入>>> ");
            String msg = sc.nextLine();

            if("exit".equals(msg)){
                System.out.println("欢迎再来!");
                dos.close();  // 关闭数据输出流管道
                socket.close();  // 释放连接资源
                break;
            }
            // 4. 开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();
        }

    }
}
// 服务端

package login;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动---");

        // 1. 创建 ServerSocket 的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2. 使用 serverSocket 对象,调用一个 accept 方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();

        // 3. 从 socket 通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();

        // 4. 把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        while (true) {

            try {
                // 5. 使用数据输入流读取客户端发送过来的消息
                String res = dis.readUTF();
                System.out.println(res);
            } catch (Exception e) {
                System.out.println(socket.getRemoteSocketAddress()+"断开了连接");;
                socket.close();
                break;
            }
        }

    }
}
多个客户端同时使用服务端
// 客户端

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建 Socket 对象,并同时请求与服务器程序的连接
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2. 从 socket 通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();

        // 3. 把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入>>> ");
            String msg = sc.nextLine();

            if("exit".equals(msg)){
                System.out.println("欢迎再来!");
                dos.close();  // 关闭数据输出流管道
                socket.close();  // 释放连接资源
                break;
            }
            // 4. 开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}
// 服务端

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("---服务端启动---");

        // 创建 ServerSocket 的对象,同时为服务端注册端口
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            // 使用 serverSocket 对象,调用一个 accept 方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();
            System.out.println(socket.getRemoteSocketAddress() + "连接到了服务端");
            // 使用一个独立的线程,把当前的 socket 对象交给它负责处理
            new ServerReaderThread(socket).start();
        }
    }
}

class ServerReaderThread extends Thread {
    private Socket socket;

    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            // 从 socket 通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            // 把原始的字节输入流包装成数据输入流
            DataInputStream dis = new DataInputStream(is);

            while (true) {
                try {
                    // 使用数据输入流读取客户端发送过来的消息
                    String res = dis.readUTF();
                    System.out.println(res);
                } catch (Exception e) {
                    System.out.println(socket.getRemoteSocketAddress() + "断开了连接");
                    dis.close();  // 关闭流管道
                    socket.close();  // 关闭连接管道
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

http://www.kler.cn/a/154816.html

相关文章:

  • 如何修改npm包
  • 力扣 最长公共前缀-14
  • 使用python-Spark使用的场景案例具体代码分析
  • 数据库的性能优化 -- SQL性能优化
  • How to install rust in Ubuntu 24.04
  • Javascript高级—常见算法
  • Spring之RestTemplate详解
  • 【3D程序软件】SideFX与上海道宁一直为设计师提供程序化 3D动画和视觉效果工具,旨在创造高质量的电影效果
  • mongoose学习记录
  • 吸烟(抽烟)检测和识别2:Pytorch实现吸烟(抽烟)检测和识别(含吸烟(抽烟)数据集和训练代码)
  • 算力基础设施领域国家标准发布
  • 2023.12.2 做一个后台管理网页(左侧边栏实现手风琴和隐藏/出现效果)
  • LeetCode - 965. 单值二叉树(C语言,二叉树,配图)
  • docker部署frp穿透内网
  • 面试数据库八股文十问十答第二期
  • VS安装QT VS Tools编译无法通过
  • Linux常用命令——atrm命令
  • 算法通关村第十四关-白银挑战堆的经典问题
  • Doris 数据导入三:Routine Load 方式
  • WIN10 WIN11 关闭更新的绝佳办法(极简单无副作用)
  • HuggingFace学习笔记--datasets的使用
  • rdf-file:SM2加解密
  • 掌握你的Mac,iStat Menus带你了解mac系统状态
  • MIT线性代数笔记-第21讲-特征值,特征向量
  • 【论文阅读】基于隐蔽带宽的汽车控制网络鲁棒认证(三)
  • MacOS qemu运行loongarch linux