# 网络编程

在通信协议下,不同计算机上运行的程序,进行的数据传输

# 常见软件架构

# CS架构(Client/Server)客户端/服务器

在用户本地需要下载并安装客户端程序,在远程有一个服务端程序

# BS架构(Browser/Server)浏览器/服务器

只需要一个浏览器,用户通过不同的网址。客户访问不同的服务器

# 网络编程三要素

  1. 确定双方ip地址
  2. 端口号 一个软件只有一个 应用程序的唯一标识 其中0~1023之间的端口号被用于一些一直的网络服务或者应用,自己使用1024以上的端口号
  3. 协议。数据在网络中的传输规则.常见协议有 UDP、TCP、HTTP、HTTPS

# 协议

# tcp/ip参考模型

tcp/ip参考模型

# udp协议

  • 用户数据报协议(User Datagram Protocol)
  • UDP是面向无连接通信协议(不管是否已经连接成功) 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

# tcp协议

  • 传输控制协议TCP(Transmission Control Protocol)
  • TCP协议是面向连接的通信协议,(使用tcp的三次握手,从而确定连接)
  • 速度慢,没有大小限制,数据安全

# inetAddress类获取本机对象

package Network;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class main {
    public static void main(String[] args) throws UnknownHostException {
        //inetAddress类 获取本机ip对象
        InetAddress byName = InetAddress.getByName("DESKTOP-ET3DHBQ");//使用当前主机名获取ip对象
        System.out.println(byName);
        System.out.println(byName.getHostName());//获取主机名称
        System.out.println(byName.getHostAddress());//获取主机ip地址

        //获取当前设备IP
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost.getHostAddress());
    }
}

# 使用UDP协议发送和接收数据

DatagramSocket类发送和接收数据

# 发送数据

public class main {
    public static void main(String[] args) throws IOException {
      //发送数据
      // 1.创建DatagramSocket对象
      //细节:
      //绑定端口号,以后我们就是通过这个端口往外发送数据
      //空参:所有可用的端口中随机一个进行使用
      //带参:指定端口号进行使用
      //1.指定端口号进行绑定
      DatagramSocket ds = new DatagramSocket();
      //2.打包数据
      byte[] bytes = "hello".getBytes();
      //3.发送的数据目的地(DESKTOP-ET3DHBQ 这台电脑)
      InetAddress address = InetAddress.getByName("DESKTOP-ET3DHBQ");
      //参数 字节数组 数据长度 目的地 端口号
      DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 10086);
      //发送数据
      ds.send(dp);
      //释放资源
      ds.close();
    }
}

# 接收数据

public class main {
  public static void main(String[] args) {
    //创建DatagramSocket对象 指定端口接口
    DatagramSocket ds = new DatagramSocket(10086);
    //创建接收字节数组
    byte[] bytes = new byte[1024];
    //接收数据
    DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
    //接收数据
    //程序在执行这一步时,会在这里死等
    //等待发送端发送消息
    ds.receive(datagramPacket);
    //释放资源
    ds.close();
    //解析数据包
    byte[] data = datagramPacket.getData();
    //获取数据包的长度
    int length = datagramPacket.getLength();
    System.out.println("发送的数据" + new String(data, 0, length));
    System.out.println("发送端主机名称" + datagramPacket.getAddress().getHostAddress());
    System.out.println("端口号" + datagramPacket.getPort());
  }
}

# UDP聊天室

package Network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class ChatRoom {
    //UDP聊天室
    public static <T> void main(String[] args) throws IOException {
        //开启发送端
        Thread thread = new Thread(new FutureTask<T>(new UDPServer<>()));
        //先开启接收端
        Thread thread1 = new Thread(new FutureTask<T>(new UDPClient<>()));
        thread.start();
        thread1.start();
    }
}

//服务器1发送数据
class UDPServer<T> implements Callable<T> {
    @Override
    public T call() throws Exception {
        //创建DatagramSocket对象 指定端口接口
        //创建对象
        DatagramSocket ds = new DatagramSocket();
        //获取键盘输入对象
        Scanner sc = new Scanner(System.in);
        //接收键盘录入
        int i = 0;
        while (i != 886) {
            System.out.println("请输入数字");
            i = sc.nextInt();
            //打包数据
            byte[] bytes = String.valueOf(i).getBytes();
            //3.发送的数据目的地(DESKTOP-ET3DHBQ 这台电脑)
            InetAddress address = InetAddress.getByName("DESKTOP-ET3DHBQ");
            //参数 字节数组 数据长度 目的地 端口号
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 10086);
            //发送数据
            ds.send(dp);
        }

        //释放资源
        ds.close();
        return null;
    }
}

//客户端1接收数据
class UDPClient<T> implements Callable<T> {
    public T call() throws Exception {
        //创建DatagramSocket对象 指定端口接口
        //创建对象
        DatagramSocket ds = new DatagramSocket(10086);
        //创建接收字节数组(新进来的数据会覆盖旧数据)
        byte[] bytes = new byte[1024];
        //定义接收格式
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
        while (true) {
            //接收数据
            ds.receive(datagramPacket);
            //数据处理
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            System.out.println("接收到的数据为" + new String(data, 0, length));
            System.out.println("接收端主机名称" + datagramPacket.getAddress().getHostAddress());
            System.out.println("端口号" + datagramPacket.getPort());
        }
    }
}

# TCP通信程序

TCP通信协议是一种可靠的网络协议.他在通信的两端各建立一个Socket对象,通信之前要保证链接已经建立

  • 通过Socket产生IO流来进行网络通信
package Network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Tcp {
    public static void main(String[] args) {
        //使用tcp协议发送数据
        //创建多线程对象 同时运行服务端和客户端
        Thread server = new Thread(new FutureTask<>(new SocketServer<>()));
        Thread client = new Thread(new FutureTask<>(new SocketClient<>()));
        //开启线程
        client.start();
        server.start();
    }
}

//客户端发送数据
class SocketClient<T> implements Callable<T> {
    @Override
    public T call() throws IOException {
        //使用tcp协议发送数据
        //发送数据使用Socket对象
        //1.创建Socket对象
        //在创建对象时同时会链接服务器
        //如果链接不上服务器 那么就会报错
        //参数(链接的ip,端口)
        Socket socket = new Socket("127.0.0.1", 10086);
        //2.可以从链接通道中获取输出流写出数据
        //注意:字节流只能写出字节数组
        socket.getOutputStream().write("你好4566".getBytes());
        return null;
    }
}

//服务端接收数据
class SocketServer<T> implements Callable<T> {
    @Override
    public T call() throws IOException {
        //使用tcp协议接收数据
        //接收数据使用ServerSocket对象
        //1.创建ServerSocket对象
        //注意发送方和接收方的端口要一致
        ServerSocket serversocket = new ServerSocket(10086);
        //2.监听客户端的链接
        //如果一直没有客户端来连 那么程序将会卡死在这行代码上
        //如果有客户端来连,那么将会返回一个Socket对象
        Socket socket = serversocket.accept();
//        //2.可以从链接通道中获取输入流读取数据
//        //注意:字节流只能读取字节数组
//        byte[] bytes = new byte[1024];
        InputStream is = socket.getInputStream();
        //将字节流转换为字符流 以便设置读取的编码规则
        InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
        //使用字符缓冲流
        BufferedReader br = new BufferedReader(isr);
        int b;
        while ((b = br.read()) != -1) {
            System.out.print("客户端发送的数据" + (char) b);
        }
        //释放资源
        socket.close();
        //关闭服务器
        serversocket.close();
        return null;
    }
}

# 文件上传

package Network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class FileTcp {
    //文件上传

    public static void main(String[] args) throws Exception {
        //创建多线程对象
        SocketFileClient socketFileClient = new SocketFileClient();
        SocketFileServer socketFileServer = new SocketFileServer();
        Thread client = new Thread(new FutureTask<>(socketFileClient));
        Thread server = new Thread(new FutureTask<>(socketFileServer));
        //开启线程
        client.start();
        server.start();
    }
}

//客户端发送文件
class SocketFileClient<T> implements Callable<T> {
    @Override
    public T call() throws Exception {
        //读取本地文件中的数据
        File file = new File("attrs\\file\\ZipStreamDemo\\网络爬虫-姓名爬取.txt");

        //创建Tcp文件传输对象
        Socket socket = new Socket("127.0.0.1", 10086);
        //创建转换流对象
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
        //获取输出流
        BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
        byte[] bytes = new byte[1024];
        int len;

        //循环读取文件
        while ((len = bufferedInputStream.read(bytes)) != -1) {
            //发送数据
            //注意一定要用socket中的输出流来写出数据
            //尽管包装成高级流,但包装完成的发送无响应
            System.out.println("发送数据" + len);
            outputStream.write(bytes, 0, len);
        }

        //释放资源
        bufferedInputStream.close();
        outputStream.close();
        //注意:要把所有流关闭才能发送结束标记 、、否则会提前结束
        //发送结束标记
        socket.shutdownOutput();
        socket.close();
        return null;
    }
}

//服务端接收文件
class SocketFileServer<T> implements Callable<T> {
    @Override
    public T call() throws Exception {
        //获取接收对象
        ServerSocket serversocket = new ServerSocket(10086);
        //监听客户端连接
        Socket socket = serversocket.accept();
        //链接成功后可以从链接通道中获取数据
        BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = new byte[1024];
        int len;
        //获取输出流对象写入本地文件
        //使用uuid 生成不重复的文件名
        File file = new File("attrs\\file\\ZipStreamDemo", "网络爬虫-姓名爬取-文件上传" + UUID.randomUUID().toString().replaceAll("-", "") + ".txt");
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
        while ((len = bufferedInputStream.read(bytes)) != -1) {
            //将获取的数据写入本地文件
            bufferedOutputStream.write(bytes, 0, len);
        }
        //传输完毕释放资源
        bufferedInputStream.close();
        bufferedOutputStream.close();
        serversocket.close();
        socket.close();
        return null;
    }
}

上次更新: 2/12/2025, 2:41:58 PM