本文讲解如何用 java 实现网络通信, 是一个非常简单的例子, 我比较喜欢能够立马看到结果, 所以先上代码再讲解具体细节.
服务端:
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.net.ServerSocket;
- import java.net.Socket;
- public class Server {
- // 搭建服务器端
- public static void main(String[] args) throws IOException {
- Server server = new Server();
- // 创建一个服务器, 即 Server
- server.oneServer();
- }
- public void oneServer() {
- try {
- ServerSocket server = null;
- server = new ServerSocket(5209);
- System.out.println("服务器启动成功");
- System.out.println("等待客户端连接");
- // 指定绑定的端口, 并监听此端口.
- Socket socket = server.accept();
- System.out.println("监听到客户端的连接");
- System.out.println("连接成功");
- // 调用 accept()方法开始监听端口, 等待客户端的连接
- String line;
- // 存储对方传过来的数据
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- // 从 socket 对象中取出对方传过来的数据
- PrintWriter writer=new PrintWriter(socket.getOutputStream());
- // 向 socket 总写如要传给对方的数据
- while ((line = in.readLine()) != null) {
- writer.println(line+"deal by servet");
- // 向客户端输出该字符串
- writer.flush();
- // 刷新输出流, 使 Client 马上收到该字符串
- System.out.println("Client:" + line);
- // 从 Client 读入一字符串, 并打印到标准输出上
- } // 继续循环
- // 关闭资源
- writer.close(); // 关闭 Socket 输出流
- in.close(); // 关闭 Socket 输入流
- socket.close(); // 关闭 Socket
- server.close(); // 关闭 server
- } catch (Exception e) {// 出错, 打印出错信息
- System.out.println("Error." + e);
- }
- }
- }
客户端:
- import java.net.Socket;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.URL;
- public class Client {
- // 搭建客户端
- public static void main(String[] args) throws IOException {
- try {
- // 创建客户端 Socket, 指定服务器地址和端口
- // Socket socket=new Socket("127.0.0.1",5200);
- System.out.println("客户端启动成功");
- Socket socket = new Socket("192.168.69.183", 5209);
- System.out.println("向服务端 5209 端口请求成功");
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- // 由系统标准输入设备读入数据, 该数据通过 writer 写到对方的 socket 中
- PrintWriter write = new PrintWriter(socket.getOutputStream());
- // 向 socket 总写入要传给对方的数据
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- // 从 socket 对象中取出对方传过来的数据
- String readline;
- readline = br.readLine(); // 从系统标准输入读入一字符串
- while (!readline.equals("end")) {
- // 若从标准输入读入的字符串为 "end" 则停止循环
- write.println(readline);
- // 将从系统标准输入读入的字符串输出到对方的 socket 中
- write.flush();
- // 打印出对方传过来的数据
- System.out.println("Server:" + in.readLine());
- // 从 Server 读入一字符串, 并打印到标准输出上
- readline = br.readLine(); // 从系统标准输入读入一字符串
- } // 继续循环
- // 关闭资源
- write.close(); // 关闭 Socket 输出流
- // in.close(); // 关闭 Socket 输入流
- socket.close(); // 关闭 Socket
- br.close();
- } catch (Exception e) {
- System.out.println("can not listen to:" + e);// 出错, 打印出错信息
- }
- }
- }
这里我们要实现的功能是客户端从键盘输入一个字符串, 发送给服务端, 服务端处理 (原字符串后加上 "deal by servet") 完成后返回给客户端. 我用的是 eclipse, 最好开两个 eclipse 一个跑客户端一个跑服务端. 先开服务端, 再开客户端(顺序不能错), 客户端输入 hello, 服务端返回 hello deal by server:
看到成果了那么可以分析一下整个通信过程.
先放一个 socket 通信模型:
三部分: 建立连接, 开始通信, 断开连接.
建立连接: 我们稍微思考一下就可以知道建立连接的过程要先存在服务端 server, 然后客户端 client 才能找, 所以要先启动服务端. 可能我们认为服务端或者说服务器是一个很神秘的东西, 其实不是, 看我们这个例子中服务端的代码:
new 一个服务器, 但是这个服务器 new 出来之后什么都没做, 我们需要调用他里面的方法让这个服务器可以运行. 所以写了一个 oneServer 方法, 服务器对象调用这个方法开始运行.
那么服务器运行的时候都干了什么呢? 看上面的模型, 服务器运行做三件事: 连接, 传送数据, 断开.
看 oneServer 中的代码, 先是创建了一个 ServerSocket 的对象, 这个对象有一个参数 5209:
ServerSocket 是专门用来创建服务器对象的, 其中的参数 5209 表示这个服务器可以通过 5209 端口被客户端连接, 即 5209 端口与创建的这个 ServerSocket 对象绑定了. 但是这个绑定只是在服务器与端口之间建立了一个通道, 我们还要能够让服务器知道有数据从外面到了这个端口, 并且因为端口不能存放数据所以需要一个 socket 来暂时存放数据. 所以有了下面的监听:
到这里, 服务器已经启动并运行了, 客户端可以连接了.
这时候启动客户端, 客户端通过 socket 连接到服务端, 指定 ip 和端口号:
客户端运行到这里表示与服务端的连接已经完成:
连接成功之后就是传送数据, 客户端创建三个对象:
br 从键盘读入要传送的数据, write 向 socket 写入要传给服务端的数据, in 从 socket 对象中取出服务端返回的数据.
服务端创建两个对象:
write 向 socket 写入要传回给客户端的数据, in 从 socket 对象中取出客户端传来的数据.
到这里数据传输的准备工作完成, 接下来就是数据传输.
客户端从键盘读入一个字符串(hello), 通过 br 读入:
然后客户端判断是否为 end, 不是 end 就继续. 通过客户端的 write, 将 readline 中的内容写到对方 (服务端) 的 socket 中, 同时使用 write 的 flush 方法通知服务端, 让服务端立马知道有数据了:
服务端监听到端口有数据之后, 通过 in 接收客户端发过来的数据, 并转成字符串, 然后处理这个字符串 (加上 deal by server) 并写到客户端的 socket 中, 同时也调用 writer 的 flush 方法通知客户端:
运行到这里, 服务端已经处理并返回了客户端发过来的数据, 在客户端的控制台中可以看到返回的数据:
服务端在自己的控制台中打印出客户端发过来的数据:
整个传送流程结束, 如果输入的字符串是 end, 那么就会跳出 while 循环, 客户端服务端各自关闭资源:
到这里, 整个过程结束.
再文字说明一下整个流程, 服务器启动 -- 服务器创建 socket 并监听 -- 客户端启动 -- 客户端创建 socket 连接服务端 -- 连接完成 -- 客户端输入数据并写到服务端的 socket 传送给服务端 -- 服务端接收到客户端传来的数据 -- 对数据进行处理 -- 处理完毕放到客户端的 socket 中 -- 客户端拿取自己 socket 中的数据 -- 打印 -- 双方断开连接.
来源: https://www.cnblogs.com/GoForMyDream/p/8710162.html