Springboot:搭建Socket服务器实现通信
1、什么是Socket?
本节内容参考:
Socket究竟是干什么的?_一人亦世界~*~的博客-CSDN博客
什么是Socket,为什么要用Socket_这个心歪了的博客-CSDN博客
TCP/IP五层标准网络架构分为:应用层、传输层、网络层、数据链路层、物理层;
各自功能及协议为:
-
应用层:具体的应用通信协议,TFTP、HTTP、……
-
传输层:提供端对端的接口,TCP、UDP
-
网络层:为数据包选择路由,IP、ICMP、RIP、OSPF、BGP、IGMP
-
数据链路层:传输带有物理地址的数据帧及错误检测,SLIP、PPP……
-
物理层:以二进制数据流的形式在物理媒体上传输数据
Socket是Java提供的基于TCP/IP协议的对整个网络传输协议架构的封装,它的作用只是使我们更方便地使用TCP/IP协议栈。它提供了针对传输层TCP或UDP编程的接口。
更详细的内容可以看之前所写的文章:TCP编程 - ShineLe - 博客园
2、使用Socket
本节内容参考:
SpringBoot+SOCKET服务端客户端_jacky 郑的博客
之前在TCP编程 - ShineLe - 博客园一文中,已经讲过如何编写Socket客户端和服务器,并在二者间利用Socket进行通信。
本节将介绍如何在Springboot中引入Socket。
整体包结构(其他层级如Dao、Service等这里就不展示了):
①Socket服务器类SocketServer.class(放在socket包中)
package com.example.electronic.socket; import java.io.IOException; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Set; public class SocketServer { //解码buffer private Charset cs = Charset.forName("UTF-8"); //接受数据缓冲区 private static ByteBuffer sBuffer = ByteBuffer.allocate(1024); //发送数据缓冲区 private static ByteBuffer rBuffer = ByteBuffer.allocate(1024); //选择器/监听器 private static Selector selector; Socket sock; public SocketServer(Socket sock){ this.sock=sock; } //启动socket服务,开始监听 public void startSocketServer(int port){ try{ //打开通信信道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //设置为非阻塞 serverSocketChannel.configureBlocking(false); //获取Socket ServerSocket serverSocket = serverSocketChannel.socket(); //打开监听器 selector = Selector.open(); //将通信信道注册到监听器 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //监听器会一直监听,如果客户端有Request就会进入到相应的事件处理 while(true){ selector.select();//select方法会一直阻塞直到相关事情发生或超时 Set<SelectionKey> selectionKeys=selector.selectedKeys();//监听到的事件 for (SelectionKey key:selectionKeys){ handle(key); } selectionKeys.clear();//清理处理过的事件 } }catch(Exception e){ e.printStackTrace(); } } //具体的事件处理方法 private void handle(SelectionKey selectionKey)throws IOException { ServerSocketChannel serverSocketChannel = null; SocketChannel socketChannel = null; String requestMsg = ""; int count = 0; if(selectionKey.isAcceptable()){ //每有客户端连接,就注册通信信道为可读 serverSocketChannel=(ServerSocketChannel)selectionKey.channel(); socketChannel=serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector,SelectionKey.OP_READ); }else if(selectionKey.isReadable()){ socketChannel=(SocketChannel)selectionKey.channel(); rBuffer.clear(); count=socketChannel.read(rBuffer); //读取数据 if(count>0){ rBuffer.flip(); requestMsg=String.valueOf(cs.decode(rBuffer).array()); } String responseMsg="已经收到客户端的消息:"+requestMsg; //返回数据 sBuffer=ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length); sBuffer.put(responseMsg.getBytes("UTF-8")); sBuffer.flip(); socketChannel.write(sBuffer); socketChannel.close(); } } }
②发布WebSocket服务
在SpringBoot的启动类(main方法中)添加如下代码:
public static void main(String[] args) throws IOException { SpringApplication.run(ElectronicApplication.class, args); ServerSocket ss = new ServerSocket(9100); while(true){ Socket sock=ss.accept(); System.out.println("connected from "+sock.getRemoteSocketAddress()); Thread t = new SocketServer(sock); t.start(); } }
相当于main方法同时启动了SpringBoot项目和Socket服务器。
③向Server发送消息
这里需要另外构造一个Client类(可以放在test中采用JUnit的方法进行测试,也可以自己构造一个新的Client的项目,这里采用第二种方法),专门用于发送消息:
import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.Scanner; public class Client { public static void main(String[]args) throws IOException { Socket sock = new Socket("localhost",9100); try(InputStream input = sock.getInputStream()){ try(OutputStream output = sock.getOutputStream()){ handle(input,output); } } sock.close(); System.out.println("disconnected."); } private static void handle(InputStream input,OutputStream output) throws IOException{ var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); var reader = new BufferedReader(new InputStreamReader(input,StandardCharsets.UTF_8)); Scanner scanner = new Scanner(System.in); System.out.println("[server] "+reader.readLine()); while(true){ System.out.print(">>> ");//打印提示 String s = scanner.nextLine();//读取一行输入 writer.write(s); writer.newLine(); writer.flush(); String resp = reader.readLine(); System.out.println("<<< "+resp); if(resp.equals("bye")){ break; } } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)