spring框架怎么写socket服务?spring-boot框架如何发布websocket服务?

我们知道,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语言有哪些类型?

json对象和json数组的区别是什么?json数组如何解析?

java打不开一闪而过要怎么办?Java如何打开运行?