我们知道,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。那spring框架怎么写socket服务?下面来我们就来给大家讲解一下。
socket服务类代码如下:
import java.io.*; import java.net.InetSocketAddress; 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; /** * nio socket服务端 */ 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服务,开启监听 * @param port * @throws IOException */ public void startSocketServer(int port) { try { //打开通信信道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //设置为非阻塞 serverSocketChannel.configureBlocking(false); //获取套接字 ServerSocket serverSocket = serverSocketChannel.socket(); //绑定端口号 serverSocket.bind(new InetSocketAddress(port)); //打开监听器 selector = Selector.open(); //将通信信道注册到监听器 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //监听器会一直监听,如果客户端有请求就会进入相应的事件处理 while (true) { selector.select(); //select方法会一直阻塞直到有相关事件发生或超时 SetselectionKeys = selector.selectedKeys(); //监听到的事件 for (SelectionKey key: selectionKeys) { handle(key); } selectionKeys.clear(); //清除处理过的事件 } } catch (Exception e) { e.printStackTrace(); } } /** * 处理不同的事件 * @param selectionKey * @throws IOException */ 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(); } } }
spring-boot框架如何发布websocket服务?
一、在服务端发布websocket服务
服务端发布websocket服务有几种方式,包括Servlet容器扫描初始化、Spring扫描初始化。我使用的是第二种方式,可以将websocket服务定义为一个单独的类实例。
Spring扫描初始化时,需要先定义一个Bean:ServerEndpointExporter,以声明服务端。我把这个Bean独立放到一个websocket 配置类中。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
接下来是定义websocket服务接口,并使用关键字 @ServerEndpoint("/websocketPath") 声明一个接口的访问路径。
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RestController; @ServerEndpoint("/logWebsocket") @Component @RestController public class LogWebSocketHandle { private Session session; //每个websocket会话连接对应一个session private static CopyOnWriteArraySetwebSocketSet = new CopyOnWriteArraySet < > (); /** * 新的WebSocket请求开启。 * 新建立连接后会触发onOpen方法 * @throws JSchException * @throws IOException */ @OnOpen public void onOpen(Session session) throws JSchException, IOException { this.session = session; webSocketSet.add(this); //服务端保留session信息,并返回结果给客户端 //这个语句用于服务端给客户端发送数据 session.getBasicRemote() .sendText("正在获取日志 "); } /** * WebSocket请求关闭。 * websocket连接关闭后,会触发onClose方法 */ @OnClose public void onClose() { webSocketSet.remove(this); } @OnError public void onError(Throwable thr) { thr.printStackTrace(); } /** * 客户端发送消息时,服务端通过onMessage方法接收 */ @OnMessage public void onMessage(String message, Session session) throws IOException, JSchException, InterruptedException { LOG.info("来自客户端的message:" + message); try { //process message //TODO } catch (IOException e) { e.printStackTrace(); } // 给客户端群发消息 // for ( Session item : webSocketSet ){ // item.getBasicRemote().sendText(message); // } } }
二、web端建立websocket连接
var websocket_host = window.location.host; //与服务端建立websocket连接 var websocket = new WebSocket("ws://" + websocket_host + "/项目名/logWebsocket"); //连接建立后,会触发onopen方法 websocket.onopen = function (event) { console.log("opened!"); $("#chart_multiple div") .append(event.data); //向服务端发送数据 websocket.send(message); }; //接收服务端的数据 websocket.onmessage = function (event) { $("#chart_multiple div") .append(event.data); $("#chart_multiple") .scrollTop( $("#chart_multiple div") .height() - $("#chart_multiple") .height() ); }
三、使用nginx转发时的额外配置
如果项目使用了nginx进行负载均衡,那么需要在nginx.conf配置文件中添加一个websocket转发配置,具体为:
location / # { websocket所在的项目名 } /logWebsocket { proxy_pass http: //ip:port/#{websocket所在的项目名}/logWebsocket; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 7200 s; }
spring-boot框架发布websocket服务可以通过以上方法进行,spring-boot的目的就是用来简化新Spring应用的初始搭建以及开发过程,所以作为开发人员我们需要掌握这些知识!最后大家如果想要了解更多java架构师知识,敬请关注奇Q工具网。
推荐阅读:
json语法规则书写格式要求有哪些?Json语言有哪些类型?