01-Java网络编程概述

nobility 发布于 2021-07-29 2715 次阅读


Java网络编程概述

网络编程本质上就是进程之间的通信,数据通信的基础就是IO模型

  • 输入流:从数据源将数据输入到我们的应用进程的数据流
  • 输出流:从我们的应用进程将数据输出到数据源

数据源:字符串、文件、对象(序列化)、Socket等都可以是数据源

JavaIO基础

JavaIO流

Socket

Linux中为了区分文件是否被打开,Linux会给每个文件分配一个整数ID,被称为文件描述符(Windows中也有类似的句柄概念,和Linux的区别还是比较大的),Linux程序在执行任何形式的I/O操作时,都是在读取或者写入一个文件描述符

Socket(插座)是网络通信的端点(绑定了IP和端口),在Linux中Socket对应着一个文件,在Java中使用一个Socket类创建一个对象就相当于创建了一个文件描述符,就可以使用普通的文件操作来传输数据

InetAddress

方法名 描述
static InetAddress getByName(String host) 根据主机名或ip地址获取InetAddress对象实例
String getHostName() 获取主机名字符串
String getHostAddress() 获取主机地址字符串

UDP

DatagramSocket类发送或接收DatagramPacket数据报

DatagramSocket
方法名 描述
void send(DatagramPacket p) 发送数据报(不检查对方是否存活,不会阻塞)
void receive(DatagramPacket p) 接受数据报(等待接收,程序会阻塞)
void close() 释放资源
DatagramPacket
方法名 描述
DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port) 包装数据报指定发送地址和端口(发送用)
DatagramPacket(byte buf[], int offset, int length) 包装数据报(接收用)

TCP

Socket类担任客户端角色,ServerSocket类担任服务端角色,当ServerSocket发现有客户端发出连接请求时,会创建Socket实例与之进行通信

Socket
方法名 描述
OutputStream getOutputStream() 获取输出流
InputStream getInputStream() 获取输入流
void close() 关闭连接资源
void shutdownInput() 输出结束标记
void shutdownOutput() 输入结束标记
ServerSocket
方法名 描述
Socket accept() 监听到有客户端连接,就对应生成与之通讯的成客户端对象

简单的CS程序实现

Server
public class Server {
  private static final int PORT = 8080;

  public static void main(String[] args) {
    try (ServerSocket serverSocket = new ServerSocket(PORT)) {
      System.out.println("服务器监听在" + PORT + "端口");
      while (true) {
        Socket socket = serverSocket.accept();  //等待客户端连接
        String prefix = "客户端[" + socket.getInetAddress() + ":" + socket.getPort() + "]";  //客户端IP和端口信息
        System.out.println(prefix + "已连接");  //客户端连接日志
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));  //获取字符缓存输入流
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));  //获取字符缓冲输出流

        String message;
        while ((message = reader.readLine()) != null) {  //若能读取到客户端一行内容
          System.out.println(prefix + "说: " + message);
          writer.write(message + "\n");  //最后加一个换行符,为了客户端能使用readLine()方法
          writer.flush();  //刷新缓冲区
        }
        System.out.println(prefix + "断开连接");
      }
    } catch (IOException e) {
      e.printStackTrace();
      System.out.println(PORT + "端口被占用");
    }
  }
}
Client
public class Client {
  private static final String HOST = "localhost";
  private static final int PORT = 8080;
  private static final String QUIT = "quit";

  public static void main(String[] args) {
    try (Socket socket = new Socket(HOST, PORT);
         Scanner scanner = new Scanner(System.in);
         BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in))) {
      BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
      System.out.println("请输入请求内容");
      while (true) {
        /*输入信息的三种方式*/
        //String info = scanner.nextLine();  //scanner标准输入流
        //String info = JOptionPane.showInputDialog("请输入请求内容");  //swing图形化输入框
        String info = consoleReader.readLine();  //字符缓冲流
        if (info != null) {
          writer.write(info + "\n");  //最后加一个换行符,为了服务端能使用readLine()方法
          writer.flush();  //刷新缓冲区
        }
        String message = reader.readLine();
        System.out.println("服务器说: " + message);
        if (QUIT.equals(message)) {  //检查是否退出连接
          break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
      System.out.println("[" + HOST + ":" + PORT + "]服务器未启动");
    }
  }
}

同步异步阻塞非阻塞

同步与异步

同步和异步指得是:被调用方返回处理结果的机制(通信机制)

  • 同步:调用方发出请求后等待返回处理结果,被调用方处理请求,处理结束后才会返回处理结果
  • 异步:调用方发出请求后等待返回处理结果,被调用方立即返回,等请求处理结束后,再使用其他方式返回给调用方处理结果

阻塞与非阻塞

阻塞与非阻塞指的是:调用方在等待调用结果时的状态(调用状态)

  • 阻塞:调用方发出请求后等待返回结果的过程中陷入阻塞状态
  • 非阻塞:调用方发出请求后等待返回结果的过程中继续执行其他的任务

不同的组合

这两组概念可以有以下四种不同的搭配

  • 同步阻塞:调用方发出请求后阻塞,被调用方处理请求,请求处理结束返回处理结果,被调用方被唤醒(类比单个线程内普通方法的调用)
  • 同步非阻塞:调用方发出请求后,被调用方直接返回,在此期间调用方抽空不断询问是否处理完成,直到被调用方将请求处理结束后,才会返回真正的处理结果,否则返回未处理完毕的状态(类比NodeJS的事件轮询机制)
  • 异步阻塞:调用方发出请求后,被调用方立刻返回,但调用方仍然是阻塞状态,直到被调用方将请求处理结束后,通知调用方获取处理结果时,调用方这才被唤醒(类比JavaScript中的forEach()方法)
  • 异步非阻塞:调用方发出请求后,被调用方立刻返回,调用方继续执行其他的任务,被调用方将请求处理结束后,再通知调用方获取处理结果(类比AJAX请求)
此作者没有提供个人介绍
最后更新于 2021-07-29