SpringBoot + netty-socketio實現服務器端消息推送

首先:因爲工作需要,需要對接socket.io框架對接,所以目前只能使用netty-socketio。websocket是不支持對接socket.io框架的。
netty-socketio顧名思義他是一個底層基於netty’實現的socket。
在springboot項目中的集成,請看下面的代碼

maven依賴

<dependency>
	<groupId>com.corundumstudio.socketio</groupId>
	<artifactId>netty-socketio</artifactId>
	<version>1.7.11</version>
</dependency>

下面就是代碼了
首先是配置參數

#socketio配置
socketio:
  host: localhost
  port: 9099
  # 設置最大每幀處理數據的長度,防止他人利用大數據來攻擊服務器
  maxFramePayloadLength: 1048576
  # 設置http交互最大內容長度
  maxHttpContentLength: 1048576
  # socket連接數大小(如只監聽一個端口boss線程組爲1即可)
  bossCount: 1
  workCount: 100
  allowCustomRequests: true
  # 協議升級超時時間(毫秒),默認10秒。HTTP握手升級爲ws協議超時時間
  upgradeTimeout: 1000000
  # Ping消息超時時間(毫秒),默認60秒,這個時間間隔內沒有接收到心跳消息就會發送超時事件
  pingTimeout: 6000000
  # Ping消息間隔(毫秒),默認25秒。客戶端向服務器發送一條心跳消息間隔
  pingInterval: 25000

上面的註釋寫的很清楚。下面是config代碼

import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * kcm
 */
@Component
public class PushServer implements InitializingBean {

    @Autowired
    private EventListenner eventListenner;

    @Value("${socketio.port}")
    private int serverPort;

    @Value("${socketio.host}")
    private String serverHost;

    @Value("${socketio.bossCount}")
    private int bossCount;

    @Value("${socketio.workCount}")
    private int workCount;

    @Value("${socketio.allowCustomRequests}")
    private boolean allowCustomRequests;

    @Value("${socketio.upgradeTimeout}")
    private int upgradeTimeout;

    @Value("${socketio.pingTimeout}")
    private int pingTimeout;

    @Value("${socketio.pingInterval}")
    private int pingInterval;

    @Override
    public void afterPropertiesSet() throws Exception {
        Configuration config = new Configuration();
        config.setPort(serverPort);
        config.setHostname(serverHost);
        config.setBossThreads(bossCount);
        config.setWorkerThreads(workCount);
        config.setAllowCustomRequests(allowCustomRequests);
        config.setUpgradeTimeout(upgradeTimeout);
        config.setPingTimeout(pingTimeout);
        config.setPingInterval(pingInterval);

        SocketConfig socketConfig = new SocketConfig();
        socketConfig.setReuseAddress(true);
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        config.setSocketConfig(socketConfig);

        SocketIOServer server = new SocketIOServer(config);
        server.addListeners(eventListenner);
        server.start();
        System.out.println("啓動正常");
    }
}

在就是監聽代碼

import com.corundumstudio.socketio.SocketIOClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * kcm
 */
@Component
public class ClientCache {

    //本地緩存
    private static Map<String, HashMap<UUID, SocketIOClient>> concurrentHashMap=new ConcurrentHashMap<>();
    /**
     * 存入本地緩存
     * @param userId 用戶ID
     * @param sessionId 頁面sessionID
     * @param socketIOClient 頁面對應的通道連接信息
     */
    public void saveClient(String userId, UUID sessionId,SocketIOClient socketIOClient){
        if(StringUtils.isNotBlank(userId)){
            HashMap<UUID, SocketIOClient> sessionIdClientCache=concurrentHashMap.get(userId);
            if(sessionIdClientCache==null){
                sessionIdClientCache = new HashMap<>();
            }
            sessionIdClientCache.put(sessionId,socketIOClient);
            concurrentHashMap.put(userId,sessionIdClientCache);
        }
    }
    /**
     * 根據用戶ID獲取所有通道信息
     * @param userId
     * @return
     */
    public HashMap<UUID, SocketIOClient> getUserClient(String userId){
        return concurrentHashMap.get(userId);
    }
    /**
     * 根據用戶ID及頁面sessionID刪除頁面鏈接信息
     * @param userId
     * @param sessionId
     */
    public void deleteSessionClient(String userId,UUID sessionId){
        concurrentHashMap.get(userId).remove(sessionId);
    }
}

下面是存儲客戶端連接信息

import com.corundumstudio.socketio.SocketIOClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * kcm
 */
@Component
public class ClientCache {

    //本地緩存
    private static Map<String, HashMap<UUID, SocketIOClient>> concurrentHashMap=new ConcurrentHashMap<>();
    /**
     * 存入本地緩存
     * @param userId 用戶ID
     * @param sessionId 頁面sessionID
     * @param socketIOClient 頁面對應的通道連接信息
     */
    public void saveClient(String userId, UUID sessionId,SocketIOClient socketIOClient){
        if(StringUtils.isNotBlank(userId)){
            HashMap<UUID, SocketIOClient> sessionIdClientCache=concurrentHashMap.get(userId);
            if(sessionIdClientCache==null){
                sessionIdClientCache = new HashMap<>();
            }
            sessionIdClientCache.put(sessionId,socketIOClient);
            concurrentHashMap.put(userId,sessionIdClientCache);
        }
    }
    /**
     * 根據用戶ID獲取所有通道信息
     * @param userId
     * @return
     */
    public HashMap<UUID, SocketIOClient> getUserClient(String userId){
        return concurrentHashMap.get(userId);
    }
    /**
     * 根據用戶ID及頁面sessionID刪除頁面鏈接信息
     * @param userId
     * @param sessionId
     */
    public void deleteSessionClient(String userId,UUID sessionId){
        concurrentHashMap.get(userId).remove(sessionId);
    }
}

控制層推送方法

@RestController
@RequestMapping("/push")
public class PushController {
    @Resource
    private ClientCache clientCache;

    @Autowired
    private JwtSupport jwtSupport;

    @GetMapping("/message")
    public String pushTuUser(@Param("id") String id){
        Integer userId = jwtSupport.getApplicationUser().getId();
        HashMap<UUID, SocketIOClient> userClient = clientCache.getUserClient(String.valueOf(userId));
        userClient.forEach((uuid, socketIOClient) -> {
            //向客戶端推送消息
            socketIOClient.sendEvent("chatevent","服務端推送消息");
        });
        return "success";
    }
}

以上代碼就是完整的實例,同學們發現什麼問題的話歡迎指教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章