基本流程
客户端发送信息(指定目标客户端)至固定的一个服务端,服务端接收信息进行处理后发送至相应的客户端
通讯核心类
Socket类与流相辅相成,完成通讯。在accept方法返回了一个Socket对象后,获取socket的输入输出流,就可以接收信息或发送信息了,以一对一为例:
服务端 :
import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * @ClassName Server * @Description 服务端 * @Author issac * @Date 2021/4/13 17:26 */ public class Server { public static void main(String[] args) throws I<mark>本文来源gaodaimacom搞#^代%!码&网(</mark>OException { // 创建服务端套接字并指定端口 ServerSocket server = new ServerSocket(88); // 接收创建建立,返回连接创建好后服务器的socket对象 Socket socket = server.accept(); InputStreamReader reader = new InputStreamReader(socket.getInputStream()); BufferedReader bufferedReader = new BufferedReader(reader); // 获取请求 String request = bufferedReader.readLine(); System.out.println("client say:" + request); // 写到输出流传递给客户端 PrintWriter writer = new PrintWriter(socket.getOutputStream()); String line = "hello too"; writer.println(line); writer.flush(); // 关闭处理流的工具、socket套接字、服务套接字 writer.close(); bufferedReader.close(); socket.close(); server.close(); } }
客户端 :
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; /** * @ClassName Client * @Description 客户端 * @Author issac * @Date 2021/4/13 17:26 */ public class Client { public static void main(String[] args) throws IOException { // 创建socket连接,指明其地址和端口 Socket socket = new Socket("127.0.0.1", 88); // 获取套接字的输出流,输出hello PrintWriter writer = new PrintWriter(socket.getOutputStream()); String readLine = "Hello"; writer.println(readLine); writer.flush(); // 从套接字的输入流中获取信息 InputStreamReader reader = new InputStreamReader(socket.getInputStream()); BufferedReader bufferedReader = new BufferedReader(reader); String respond = bufferedReader.readLine(); System.out.println("server say:" + respond); bufferedReader.close(); writer.close(); socket.close(); } }
运行结果:
需要注意的是accept方法在没有连接的时候会阻塞,而导致后面的代码无法执行,在接下来的多对多通讯中需要依靠多线程来解决这个问题。
多对多代码实现
为了方便服务端和客户端对信息的处理,解析。首先定义一个消息类,定义属性分别为端口的本地地址,发送的消息内容,发送的目标地址。定义静态方法:将字符串解析为该类实例,处理消息的收发:
import com.alibaba.fastjson.JSON; import java.io.Serializable; import com.alibaba.fastjson.JSON; import java.io.*; import java.net.Socket; /** * 在网络中,所有被进行通讯的对象,都需要实现 Serializable 这个接口 * <p> * 该类,主要用于本项目例子中,socket传输的对象,请勿使用其他或字符串, * 为了后期更方便修改或者是其他操作 * * @ClassName SocketMessage * @Description TODO * @Author issac * @Date 2021/4/18 22:02 */ public class SocketMessage implements Serializable { /** * 我自己的名称 ip:port **/ private String key; /** * 我的目标 ip:port **/ private String to; /** * 发送的内容 **/ private String content; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } /** * 向目标客户端写出从发送者获取到的消息 */ public static void writeTargetMessage(SocketMessage message, Socket socket) throws IOException { PrintWriter writer = new PrintWriter(socket.getOutputStream()); // 统一字符串标准,以便于服务端解析 writer.println(JSON.toJSONString(message)); writer.flush(); } /** * 将输入流中接收的字符串解析为SocketMessage对象 * * @param is * @return SocketMessage * @throws Exception */ public static SocketMessage parseSocket(InputStream is) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String info = reader.readLine(); return parseSocketByStr(info); } /** * 将传入字符串解析为SocketMessage对象并返回 * * @param str * @return SocketMessage */ public static SocketMessage parseSocketByStr(String str) { SocketMessage socketMessage = null; try { socketMessage = JSON.parseObject(str, SocketMessage.class); } catch (Exception ex) { throw new RuntimeException("socket之间通讯不能不使用SocketMessage"); } return socketMessage; } @Override public String toString() { // 通过 阿里巴巴 的FastJson 库,将一个对象转换为 字符串 ,统一标准,以便于将字符串解析为该类 return JSON.toJSONString(this); } }