第一部分:为什么是java?如何在liunx上安装java?
最核心的一点:java“一次编写,到处运行” 的理念给予了它极为优异的跨平台性能。Java 支持 Linux、Windows、ARM/x86 等环境,并与 Kubernetes、Docker 无缝集成。
只要你的电脑上安装了java jdk环境,无论是Windows还是liunx都可以运行java应用,所以我们的第一步,就是为服务器配置java环境:
方法一:使用宝塔面板安装java jdk:
在软件商店中搜索“java环境管理器”,然后下载安装,完成后打开它:
再选择相应版本安装即可。
方法二:在终端进行操作:
这里以Ubuntu系统安装java17为例:
sudo apt update sudo apt install openjdk-17-jdk -y无论哪种方法,在安装完成后都可以查询java版本验证:
java -version如果安装成功,终端会输出如下信息:
第二部分:基于WebSocket的服务器通信原理及简单的信息处理尝试
我们现在知道服务器的ip了,那我们该如何让我们的本地计算机链接到它呢?
答案是使用WebSocket。WebSocket是一种重要的网络通信协议,属于传输层之上的应用层协议,提供全双工通信通道,允许客户端与服务器双向传输数据,提供了一套api接口来使计算机之间能够建立链接。几乎所有的编程语言都支持WebSocket。我们熟知的spring框架中的spring WebSocket就是对前者的封装。
在实际应用中,我们需要根据实际情况来选择使用WebSocket还是spring WebSocket:
WebSocket虽然在编程调用上比较麻烦,但功能可扩展性高。原生 WebSocket 支持通过 RFC 6455 定义的扩展机制(如permessage-deflate压缩、心跳检测)动态增强协议功能,适用于需要深度定制的场景(如高吞吐量二进制数据传输)。
Spring WebSocket在编程使用的简便性上更优,相应的它的扩展灵活性相对弱于前者。Spring WebSocket 通过@MessageMapping、@SubscribeMapping等注解,将消息路由和处理逻辑封装为类似 Spring MVC 的声明式编程模型,开发者无需手动处理连接生命周期(如onopen、onmessage事件)或底层帧解析。
具体到通信协议中的TCP协议、UDP协议等等我们后面再详细去讲,简单来说,这些协议规定了客户端与服务器之间谁怎样发送数据,谁又如何接收数据等等。
接下来我们讲解基于WebSocket的服务器通信实现功能的关键字段(为方便读代码,这些代码简化去除了异常处理类),假定我们要实现的功能是客户端发送两个数字A和B,服务器返回C=A+B,代码分为服务器端(cloud)与客户端(local)(完整代码在放在最后):
第一步,在本地构造一个包含了服务器ip与端口的local:
//local.java public local(String serverIp, int serverPort) { this.serverIp = serverIp; //服务器ip this.serverPort = serverPort; //服务器端口 }第二步,创建socket在客户端的服务进程:
//local.java public int sendAndProcessData(int a, int b) throws IOException { Socket socket = new Socket(serverIp, serverPort); // 创建(实例化)客户端套接字,连接到指定IP地址和端口的服务器 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // 获取套接字的输出流,用于向服务器发送数据 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 获取套接字的输入流,用于读取服务器返回的数据第三步,创建socket在服务器的进程:
//cloud.java public void start() throws IOException { serverSocket = new ServerSocket(port); //创建(实例化)一个服务器套接字,监听指定端口 System.out.println("服务器启动,监听端口: " + port); while (true) { Socket clientSocket = serverSocket.accept(); // 等待客户端连接请求,当有客户端连接时返回客户端套接字 System.out.println("客户端已连接: " + clientSocket.getInetAddress()); //在建立连接后,输出日志+客户端ip new ClientHandler(clientSocket).start(); // 创建新线程处理客户端请求 } }第四步,编写服务器与客户端的数据处理逻辑:
//cloud.java private static class ClientHandler extends Thread { private Socket clientSocket; public ClientHandler(Socket socket) { this.clientSocket = socket; } @Override public void run() { try ( BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true) ) { // 读取两个整数 String line = in.readLine(); String[] numbers = line.split(","); int a = Integer.parseInt(numbers[0].trim()); int b = Integer.parseInt(numbers[1].trim()); int c = a + b; // 返回计算结果 out.println(c); System.out.println("处理完成: " + a + " + " + b + " = " + c); clientSocket.close(); } catch (Exception e) { // 简化异常处理 } } }//local.java的sendAndProcessData的后半部分: // 发送数据A和B String requestData = a + "," + b; out.println(requestData); // 接收处理结果C String response = in.readLine(); int result = Integer.parseInt(response); // 关闭资源 in.close(); out.close(); socket.close(); return result; }最后一步:编写服务器与客户端的主方法:
//local.java public static void main(String[] args) throws IOException { String serverIp = "xxx.xxx.xxx.xxx"; //替换为你的服务器的ip int serverPort = 1234; //注意别忘了放通服务器防火墙 local client = new local(serverIp, serverPort); int a = 10; int b = 20; int c = client.sendAndProcessData(a, b); System.out.println("发送数据: A=" + a + ", B=" + b); System.out.println("接收结果: C=" + c); }//cloud.java public static void main(String[] args) throws IOException { cloud server = new cloud(1234); // 一定一定要使用与客户端相同的端口号 server.start(); }我们来试运行一下代码,先将cloud.java上传到你的服务器当中,再在服务器终端上使用java指令运行cloud.java,再在本地运行local.java:
本地终端输出:
服务器终端输出(涂红部分是客户端ip):
可以体会到,原生WebSocket确实在调用上比较麻烦,在下一节中,我们将研究如何使用spring来连接服务器。
附:本节原生WebSocket实现功能的代码:
客户端(local.java):
// local.java package cloudtest; import java.io.*; import java.net.*; public class local { private String serverIp; private int serverPort; public local(String serverIp, int serverPort) { this.serverIp = serverIp; this.serverPort = serverPort; } public int sendAndProcessData(int a, int b) throws IOException { Socket socket = new Socket(serverIp, serverPort); // 创建客户端套接字,连接到指定IP地址和端口的服务器 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // 获取套接字的输出流,用于向服务器发送数据 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 获取套接字的输入流,用于读取服务器返回的数据 // 发送数据A和B String requestData = a + "," + b; out.println(requestData); // 接收处理结果C String response = in.readLine(); int result = Integer.parseInt(response); // 关闭资源 in.close(); out.close(); socket.close(); return result; } public static void main(String[] args) throws IOException { String serverIp = "xxx.xxx.xxx.xxx"; int serverPort = 1234; local client = new local(serverIp, serverPort); int a = 10; int b = 20; int c = client.sendAndProcessData(a, b); System.out.println("发送数据: A=" + a + ", B=" + b); System.out.println("接收结果: C=" + c); } }服务器(cloud.java):
// cloud.java package cloudtest; import java.io.*; import java.net.*; public class cloud { private ServerSocket serverSocket; private int port; public cloud(int port) { this.port = port; } public void start() throws IOException { serverSocket = new ServerSocket(port); //创建(实例化)一个服务器套接字,监听指定端口 System.out.println("服务器启动,监听端口: " + port); while (true) { Socket clientSocket = serverSocket.accept(); // 等待客户端连接请求,当有客户端连接时返回客户端套接字 System.out.println("客户端已连接: " + clientSocket.getInetAddress()); new ClientHandler(clientSocket).start(); // 创建新线程处理客户端请求 } } // 客户端处理线程 private static class ClientHandler extends Thread { private Socket clientSocket; public ClientHandler(Socket socket) { this.clientSocket = socket; } @Override public void run() { try ( BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true) ) { // 读取两个整数 String line = in.readLine(); String[] numbers = line.split(","); int a = Integer.parseInt(numbers[0].trim()); int b = Integer.parseInt(numbers[1].trim()); int c = a + b; // 返回计算结果 out.println(c); System.out.println("处理完成: " + a + " + " + b + " = " + c); clientSocket.close(); } catch (Exception e) { // 简化异常处理 } } } public static void main(String[] args) throws IOException { cloud server = new cloud(1234); // 使用与客户端相同的端口 server.start(); } }