Java网络编程初步入门

网络的重要概念

基本概念涉及很多计网知识, 这里不过多赘述

一. IP地址

用于唯一的标识网络中的每台计算机

  1. IP地址通常使用点分十进制来表示. xx.xx.xx.xx, 每一个十进制数的范围是[0, 255]
  2. 一个IP地址分为两个部分, IP地址=网络地址+主机地址
  3. IPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议, 地址长度为128位, 是IPv4的四倍, 采用的是冒分十六进制
  4. IPv4分为A, B, C, D, E 五类地址

二. 域名和端口

  1. 域名其实是将IP地址映射成为的一段信息, 解决了记忆ip地址的困难(怎么映射涉及到HTTP协议)
  2. 端口号用于标识计算机上运行的某一个特定的网络程序, 通常以整数形式表示, 端口范围是0-65535
  3. 0-1024已经被占用, 例如ssh: 22, smtp: 25, http: 80
    常见的一些服务默认端口:

Tomcat: 8080
MySQL: 3306
Oracle: 1521
SqlServer: 1433

三. 网络通信协议

TCP/IP协议

  1. TCP协议, 是一种传输控制协议, 需要建立TCP连接, 形成传输数据通道, 采用"三次握手", 是可靠的, 进行通信的两个应用进程是客户端和服务端, 在连接中可以进行大数据量的传输, 传输完毕之后需要释放已经建立的连接, 效率低
  2. UDP协议, 是用户数据协议, 将数据, 源, 目的封装成数据报, 不需要建立连接, 每个数据报的大小限制在64K内, 因为无需链接, 故不可靠, 发送数据结束时无需释放资源, 速度快

网络编程

Java中专门提供了java.net包, 里面包含了Java网络编程所需要的类和接口

一. InetAddress

  1. 获取本机的InetAddress 对象, 然后获取本地localHost对象, 前半部分是主机名, 后半部分是地址, 中间使用"/"分割
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
  1. 根据指定的主机名获取 InetAddress对象
InetAddress inetaddress = InetAddress.getByName("xxx");
System.out.println(inetaddress);
  1. 根据域名返回, 比如www.baidu.com
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println(baidu);
  1. 通过InetAddress对象, 获取对应地址
System.out.println(baidu.getHostAddress());
  1. 通过InetAddress对象, 获取对应的域名/主机名
System.out.println(baidu.getHostName());

二. Socket

套接字(Socket)在开发网络应用程序中被广泛采用, 以至于成为事实上的标准, 通信的两端都要有Socket, 是两台机器间通信的端点, 网络通信其实就是Socket之间的通信

1. 介绍
Socket允许程序把网络连接当成一个流, 数据在两个Socket间通过IO传输. 一般主动发起通信的应用程序属于客户端, 等待通信请求的为服务端

2. 使用
可以使用Socket来获取输入输出流, 从而达到读写的目的
使用Socket可以进行TCP编程和UDP编程

三. TCP编程

1. 传输数据

要求: 利用端口9999, 在本机设立客户端和服务端, 客户端向服务端写入"hello, server", 服务端读取之后输出出来

服务端:

public class TCPStreamServer {
    public static void main(String[] args) throws IOException {
        // 1. 在本机9999端口监听, 等待连接, 要求本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);

        // 2. 当没有客户端连接9999端口时, 程序会阻塞, 等待连接
        // 如果有, 则会返回Socket对象, 程序继续
        // 这个serverSocket可以通过accept()方法返回多个Socket -> 多并发
        Socket socket = serverSocket.accept();

        InputStream inputStream = socket.getInputStream();

        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }

        inputStream.close();
        socket.close();
        System.out.println("服务端退出");
    }
}

客户端

public class TCPStreamClient {
    public static void main(String[] args) throws IOException {
        // 1. 连接服务器(ip, 端口)
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        // 2. 得到和socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();

        // 3. 通过输出流写数据, 在数据末尾一定要加入结束标记, 表示后面已经没有内容
        outputStream.write("hello, server".getBytes());
        socket.shutdownOutput();
        
        // 4. 关闭流对象和客户端
        outputStream.close();
        socket.close();
        System.out.println("客户端退出");
    }
}

注意:

  1. socket只能获取字节流, 如果想使用字符流, 需要使用转换流
  2. 字符流中结束标记为writer.newLine(), 但是这里注意, 如果想要读取到结束标记, 必须使用writer.readLine(), 否则会读取不到
  3. 写入完之后要记得flush()

2. 传输文件

要求: 将客户端的图片, 通过网络上传到服务端, 服务端回复消息
客户端

public class TCPStreamClient {
    public static void main(String[] args) throws IOException {
        //1. 客户端连接服务端
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        // 2. 将本地的图片读取出来
        String path = "D:\\mypile\\acm\\qie.jpg";
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));

        // 3. 这里面就是文件对应的字节数组
        byte[] bytes = streamToByteArray(bufferedInputStream);

        // 4. 通过socket获取到输出流, 将数据发送到服务端
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        bufferedOutputStream.write(bytes);
        socket.shutdownOutput();

        // 5. 获取服务端传来的信息
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }

        // 5. 关闭流和socket
        bufferedOutputStream.close();
        bufferedInputStream.close();
        socket.close();
        bufferedReader.close();

    }

    public static byte[] streamToByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];

        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        byte[] arrays = bos.toByteArray();
        bos.close();
        return arrays;
    }
}

服务端

public class TCPStreamServer {
    public static void main(String[] args) throws IOException {
        //1. 服务端在本机监听8888端口
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2. 等待连接
        Socket socket = serverSocket.accept();

        // 3. 读取客户端发送的数据, 通过Socket得到输入流
        BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = streamToByteArray(bufferedInputStream);

        // 4. 将bytes数组写入指定的路径
        String path = "src\\qie.jpg";
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(path));

        bufferedOutputStream.write(bytes);

        // 5. 向客户端回复收到图片
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bufferedWriter.write("收到图片");
        bufferedWriter.flush();
        socket.shutdownOutput();


        // 关闭资源
        bufferedOutputStream.close();
        bufferedInputStream.close();
        bufferedWriter.close();
        socket.close();
        serverSocket.close();
    }

    public static byte[] streamToByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];

        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        byte[] arrays = bos.toByteArray();
        bos.close();
        return arrays;
    }
}

四. UDP编程

基本介绍

  1. DatagramSocketDatagramPacket实现了基于UDP 协议网络程序。
  2. UDP数据报通过数据报套接字 DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
  3. DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
  4. UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

具体例子
发送端

public class UDPSender {
    public static void main(String[] args) throws IOException {
        // 1. 创建一个DatagramSocket 对象, 在指定端口发送数据,
        // 注意, 如果是同一台设备发送和接受, 不要使用一样的端口
        DatagramSocket datagramSocket = new DatagramSocket(9998);

        // 2. 将需要发送的数据封装到数据报中
        byte[] bytes = "hello".getBytes();
        DatagramPacket datagramPacket =
                new DatagramPacket(bytes, bytes.length, InetAddress.getByName("Ethereal"), 9999);

        // 3. 发送数据报
        datagramSocket.send(datagramPacket);

        // 4. 关闭资源
        datagramSocket.close();
        System.out.println("发送完成");

    }
}

接收端

public class UDPReceiver {
    public static void main(String[] args) throws IOException {
        // 1. 创建一个DatagramSocket 对象, 在指定端口接收数据
        DatagramSocket datagramSocket = new DatagramSocket(9999);

        // 2. 构建一个DatagramPacket 对象, 用来接受数据, 在UDP中一个数据报最大64K
        byte[] bytes = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(bytes, 1024);

        // 3. 调用方法, 将通过网络传输的DatagramPacket对象填充到本地
        // 注意: 当有数据报发送到9999端口时会接收到, 但是如果没有的话就会阻塞, 等待数据报
        datagramSocket.receive(datagramPacket);

        // 4. 可以把收到的数据报进行拆包, 从而获得数据
        int length = datagramPacket.getLength(); // 数据的长度
        byte[] data = datagramPacket.getData(); // 数据的内容

        String s = new String(data, 0, length);
        System.out.println(s);

        // 5. 关闭资源
        datagramSocket.close();
        System.out.println("接收完成");
    }
}

posted @   Xingon2356  阅读(6)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示