Spingboot 整合netty-socket.io

这篇具有很好参考价值的文章主要介绍了Spingboot 整合netty-socket.io。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spingboot 整合netty-socket.io

  1. 依赖

    注意版本号,不然client版本不对的话也是连不上的

    https://github.com/mrniko/netty-socketio

​ ``

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


<zyy-socket.version>2.0.2</zyy-socket.version>
  1. 结构

Spingboot 整合netty-socket.io,java,websocket,java,后端

3 配置

package com.zyy.wss.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.zyy.framework.model.constant.SecurityConstants;
import com.zyy.wss.handler.NettySocketEventHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author: liucw
 * @createDate: 2023/4/26
 * @description:
 */


@Configuration
@Slf4j
public class NettySocketConfig {
    @Value("${socket.port}")
    private Integer socketPort;
    @Value("${socket.upgradeTimeout}")
    private Integer upgradeTimeout;
    @Value("${socket.pingInterval}")
    private Integer pingInterval;
    @Value("${socket.pingTimeout}")
    private Integer pingTimeout;

    @Value("${socket.bossThreadCount}")
    private Integer bossThreadCount;

    @Value("${socket.workerThreadCount}")
    private Integer workerThreadCount;
    @Resource
    private NettySocketEventHandler nettySocketEventHandler;


    @Resource
    private TokenStore tokenStore;

    @Bean
    public SocketIOServer socketIOServer() {
        /*
         * 创建Socket,并设置监听端口
         */
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        // 设置主机名,默认是0.0.0.0
        config.setHostname("0.0.0.0");
        // 设置监听端口
        config.setBossThreads(bossThreadCount);
        config.setWorkerThreads(workerThreadCount);
        config.setAllowCustomRequests(true);
        config.setPort(socketPort);
        // 协议升级超时时间(毫秒), 默认10000, HTTP握手升级为ws协议超时时间
        config.setUpgradeTimeout(upgradeTimeout);
        // Ping消息间隔(毫秒), 默认25000, 客户端向服务器发送一条心跳消息间隔
        config.setPingInterval(pingInterval);
        // Ping消息超时时间(毫秒), 默认60000, 这个时间间隔内没有接收到心跳消息就会发送超时事件
        config.setPingTimeout(pingTimeout);
        // 开放跨域 null 不是*
        config.setOrigin("*");
        SocketConfig socketConfig = new SocketConfig();
        socketConfig.setReuseAddress(true);
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        config.setSocketConfig(socketConfig);

        config.setAuthorizationListener(handshakeData -> {
            Map<String, List<String>> urlParams = handshakeData.getUrlParams();
            String accessToken = handshakeData.getSingleUrlParam("Authorization");
            log.info(" handshakeData  url  req :{} ,authorization:{}", JSONUtil.toJsonStr(urlParams), accessToken);
            if (StrUtil.isBlank(accessToken)) {
                return false;
            }
            OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(StrUtil.replaceIgnoreCase(accessToken, SecurityConstants.JWT_PREFIX, Strings.EMPTY));
            return !oAuth2AccessToken.isExpired();
        });
        SocketIOServer socketIOServer = new SocketIOServer(config);
        socketIOServer.addListeners(nettySocketEventHandler);
        return socketIOServer;
    }

    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
        return new SpringAnnotationScanner(socketServer);
    }
}

4 .ClientCache

``

package com.zyy.wss.config;

import com.corundumstudio.socketio.SocketIOClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

/**
 * @author litong
 * @date 2019/11/6 16:01
 */
@Component
@Slf4j
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) {
        HashMap<UUID, SocketIOClient> sessionIdClientCache = concurrentHashMap.get(userId);
        if (sessionIdClientCache == null) {
            sessionIdClientCache = new HashMap<>();
        }
        sessionIdClientCache.put(sessionId, socketIOClient);
        concurrentHashMap.put(userId, sessionIdClientCache);

        log.info("ClientCache :{}",concurrentHashMap.get(userId).size());

    }

    /**
     * 根据用户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);
    }
}

5 . 连接处理类

package com.zyy.wss.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.zyy.admin.api.dto.common.NumberNotDownloadedDto;
import com.zyy.admin.api.enums.common.ExportEnums;
import com.zyy.common.api.feign.DownloadCenterFeign;
import com.zyy.framework.model.dto.result.data.DataResult;
import com.zyy.framework.model.enums.TenantEnums;
import com.zyy.framework.model.enums.base.EnumUtils;
import com.zyy.wss.config.ClientCache;
import com.zyy.wss.entity.DownLoadData;
import com.zyy.wss.entity.MessageInfoStructure;
import com.zyy.wss.entity.TokenInfo;
import com.zyy.wss.enums.MsgTypeEnum;
import com.zyy.wss.helper.JWTHelper;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.UUID;

/**
 * @author: liucw
 * @createDate: 2023/4/26
 * @description:
 */
@Component
@Slf4j
public class NettySocketEventHandler {
    @Resource
    private ClientCache clientCache;
    @Resource
    private JWTHelper jwtHelper;
    @Resource
    private DownloadCenterFeign downloadCenterFeign;

    /**
     * socket事件消息接收入口
     */
    @OnEvent(value = "message_event") //value值与前端自行商定
    public void onEvent(SocketIOClient client, AckRequest ackRequest, MessageInfoStructure data) {
        boolean ackRequested = ackRequest.isAckRequested();
        // 获取前端推送数据
        log.info("onEvent :{}", JSONUtil.toJsonStr(data));
        //根据msgType类别进行数据类型判断,
        if (Objects.nonNull(data.getMsgType()) && data.getMsgType().equals(MsgTypeEnum.EXPORT_POLLING.getValue())) {
            TokenInfo clientKey = jwtHelper.getClientKey(client);
            assert clientKey != null;
            DataResult<Integer> integerDataResult = null;
            if (data.getTenantId().equals(TenantEnums.ZMP_BACK.getId())) {
                integerDataResult = downloadCenterFeign.downloadableCount(NumberNotDownloadedDto.builder().userType(ExportEnums.ExportUserType.DAY_PIVOT.getUserType()).userId(clientKey.getUserId()).build());
            } else if (data.getTenantId().equals(TenantEnums.ZMP_BEND.getId())) {
                integerDataResult = downloadCenterFeign.downloadableCount(NumberNotDownloadedDto.builder().userType(ExportEnums.ExportUserType.CLOUD_CHAIN.getUserType()).userId(clientKey.getCustomerId()).build());
            }
            log.info("integerDataResult :{}", JSONUtil.toJsonStr(integerDataResult));
            if (StrUtil.isNotBlank(data.getMsgContent())) {
                DownLoadData downLoadData = (DownLoadData) JSONUtil.toBean(data.getMsgContent(), EnumUtils.of(MsgTypeEnum.class, MsgTypeEnum.EXPORT_POLLING.getValue()).getContentType());
                log.info("Json: " + downLoadData);
            }
            //数据类型标识
            //向前端发送接收数据成功标识
            //这里可填写接收数据后的相关业务逻辑代码
            client.sendEvent("message_event", integerDataResult);

        }

    }

    /**
     * socket添加@OnDisconnect事件,客户端断开连接时调用,刷新客户端信息
     */

    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        log.info("--------------------客户端已断开连接--------------------");
        //client.disconnect();
        TokenInfo clientKey = jwtHelper.getClientKey(client);
        if (Objects.isNull(clientKey)) {
            log.error("Client key token error");
            return;
        }
        clientCache.deleteSessionClient(String.valueOf(clientKey.getUserId()), client.getSessionId());
    }

    /**
     * socket添加connect事件,当客户端发起连接时调用
     */
    @OnConnect
    public void onConnect(SocketIOClient client) {
        if (client != null) {
            TokenInfo clientKey = jwtHelper.getClientKey(client);
            if (Objects.isNull(clientKey)) {
                log.error("Client key token error");
                return;
            }
            //存储SocketIOClient,用于向不同客户端发送消息
            // socketIOClientMap.put(mac, client);
            UUID sessionId = client.getSessionId();
            clientCache.saveClient(String.valueOf(clientKey.getUserId()), sessionId, client);
            log.info("--------------------客户端连接成功---------------------");

            client.sendEvent("connected", "connected", sessionId);
        } else {
            log.error("客户端为空");
        }
    }

    /**
     * 广播消息 函数可在其他类中调用
     */
/*    public static void sendBroadcast(byte[] data) {
        for (SocketIOClient client : socketIOClientMap.values()) {
            //向已连接的所有客户端发送数据,map实现客户端的存储
            if (client.isChannelOpen()) {
                client.sendEvent("message_event", data);
            }
        }
    }*/
}

6.工具处理类

package com.zyy.wss.helper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import com.corundumstudio.socketio.SocketIOClient;
import com.google.common.collect.Maps;
import com.nimbusds.jose.JWSObject;
import com.zyy.framework.model.constant.SecurityConstants;
import com.zyy.wss.entity.TokenInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Map;

/**
 * @author: liucw
 * @createDate: 2023/4/28
 * @description:
 */

@Component
@Slf4j
public class JWTHelper {

    @Resource
    private TokenStore tokenStore;


    public static Boolean verifyZyToken(String token) {

        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
        String payload;
        try {
            payload = StrUtil.toString(JWSObject.parse(token).getPayload());
        } catch (ParseException e) {
            log.error("验证token失败", e);
            return false;
        }
        TokenInfo tokenInfo = JSONUtil.toBean(payload, TokenInfo.class);
        log.info("token: {}", tokenInfo);
        return tokenInfo.isAuth();
    }

    public static TokenInfo parseZyToken(String token) {

        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
        String payload;
        try {
            payload = StrUtil.toString(JWSObject.parse(token).getPayload());
        } catch (ParseException e) {
            log.error("验证token失败", e);
            return null;
        }
        return JSONUtil.toBean(payload, TokenInfo.class);

    }

    public TokenInfo parseZyTokenTwo(OAuth2AccessToken token) {
        Map<String, Object> source = token.getAdditionalInformation();
        Map<String, String> mapping = Maps.newHashMap();
        mapping.put("username", "username");
        mapping.put("customerId", "customerId");
        mapping.put("userId", "userId");
        return BeanUtil.mapToBean(source, TokenInfo.class, true, CopyOptions.create().setFieldMapping(mapping));
    }


    public TokenInfo getClientKey(SocketIOClient client) {

        String authorization = client.getHandshakeData().getSingleUrlParam("Authorization");
        if (StrUtil.isBlank(authorization)) {
            return null;
        }
        authorization = StrUtil.replaceIgnoreCase(authorization, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
        // TokenStore tokenStore = SpringContextHelper.getBean("tokenStore", TokenStore.class);
        return parseZyTokenTwo(tokenStore.readAccessToken(authorization));

    }

  /*  public static TokenInfo getClientKey(SocketIOClient client) {


        String authorization = client.getHandshakeData().getSingleUrlParam("Authorization");
        if (StrUtil.isBlank(authorization)) {
            return null;
        }
        return parseZyToken(authorization);

    }*/


    public static void main(String[] args) throws ParseException {

        String token = "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJMaWFvMSIsImlwIjoiMTEzLjExMC4yMjEuNSIsImF1dGhlbnRpY2F0aW9uSWRlbnRpdHkiOiJ1c2VybmFtZSIsImF2YXRhciI6bnVsbCwidXNlcklkIjoxNjUxNDEwMDc3MTQ5Njc5NjE4LCJhdXRob3JpdGllcyI6WyJCRU5EOklvdC9NaWZp55So5oi36L-Q6JClIl0sImNsaWVudF9pZCI6InptcC1iZW5kIiwic2NvcGUiOlsiYWxsIl0sImZpcnN0TG9naW5TdGF0dXMiOjAsInRlbmFudElkIjoxMSwiY3VzdG9tZXJJZCI6MTY1MTQxMDA3Njg1MTg1NTM2MSwiZXhwIjoxNjgyNjg4NTU5LCJqdGkiOiI2MTY5ODRiOC1jZDU3LTRmYmItOTMxMS05YzNhNTdlZjVmOTciLCJ1c2VybmFtZSI6IkxpYW8xIn0.jHwvZc3vCwDzTfPJ26-7_wfKOehmfRCxEiKe3l79up5gBaYDSIWb3lTSsdORfhmCiRBRJPvhts19DJIwa3xbieBTDUoN8eEENUBGVblHzTMCgdprms88WCtLue6-BpZ6YnEiBXK1vNLStrdi7zf7JohKwdeXb7OojgKN-5PX2yLuaPZSQMiJmCDQ597q7Lx7DkmR5MdcAqEU2bUuTrFTtqgQDcyfARAqYxra2JFVreVOjnVJoZqtIkYE16lSt5_7IEQYqgzdcccq6hnuZmD7eqcg0vh3KDO94DBZncWEu08CJZ427cpFZBL0n5rTplFFnxNHy8LtX-MiZSZkJHFKjA";
        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);

        String payload = StrUtil.toString(JWSObject.parse(token).getPayload());
        TokenInfo tokenInfo1 = JSONUtil.toBean(payload, TokenInfo.class);

        boolean auth = tokenInfo1.isAuth();
        //  TokenInfo tokenInfo = verifyToken(token);
        System.out.println(JSONUtil.toJsonStr(auth));


    }

}

7.NettySocketRunnable

package com.zyy.wss.runner;

import com.corundumstudio.socketio.SocketIOServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author: liucw
 * @createDate: 2023/4/26
 * @description:
 */

@Component
@Order(value = 1)
@Slf4j
public class NettySocketRunnable implements CommandLineRunner {

    private final SocketIOServer server;

    @Autowired
    public NettySocketRunnable(SocketIOServer server) {
        this.server = server;
    }

    @Override
    public void run(String... args) {
        log.info("--------------------SocketIOServer socket.io通信启动成功!---------------------");
        server.start();
    }
}

yaml 配置

socket:
  port: 9090
  upgradeTimeout: 10000
  pingInterval: 60000
  pingTimeout: 180000
  bossThreadCount : 1
  workerThreadCount : 100

8:nginx 配置 协议升级 wss(443) 或ws(80)

map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
   upstream socket {
        server 127.0.0.1:9090 ;
                 keepalive 256;
    }
 location /socket.io/ {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_pass http://socket;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          tcp_nodelay on;
    }

1: 注意server的版本和client版本是对应上的

2: 上线后注意线上是否有cdn 注意 如果有需要开启cdn支持websocket

1: 注意server的版本和client版本是对应上的

2: 上线后注意线上是否有cdn 注意 如果有需要开启cdn支持websocket

支持多个节点 清集群文章来源地址https://www.toymoban.com/news/detail-613978.html

public interface SocketIOService {


    void pushMessageToUser(String eventName, String userId, Object msgContent);

    void sendToAll(String eventName, Object msgContent);

    void sendMessage(String eventName, String userId, Object msgContent);
}
package com.zyy.wss.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.corundumstudio.socketio.SocketIOClient;
import com.zyy.wss.config.ClientCache;
import com.zyy.wss.config.properties.SocketIoServerProperties;
import com.zyy.wss.entity.MessageInfoStructure;
import com.zyy.wss.service.SocketIOService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * @author: liucw
 * @createDate: 2023/5/23
 * @description:
 */

@Service
@Slf4j
public class SocketIOServiceImpl implements SocketIOService {


    @Resource
    private ClientCache clientCache;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private SocketIoServerProperties serverProperties;
    /**
     * 广播(群发)前缀
     */
    private static final String MASS_PREFIX = "/mass";
    /**
     * socketio
     */
    private static final String TOPIC_SOCKETIO_SINGLE = "socketio:single";

    private static final String TOPIC_SOCKETIO_TOALL = "socketio:toAll";


    @Override
    public void pushMessageToUser(String eventName, String userId, Object msgContent) {

        HashMap<UUID, SocketIOClient> userClient = clientCache.getUserClient(userId);
        if (userClient == null) {
            log.debug("没有在线的用户");
            return;
        }
        userClient.forEach((uuid, socketIOClient) -> {
            //向客户端推送消息
            socketIOClient.sendEvent(eventName, msgContent);
        });


    }

    @Override
    public void sendToAll(String topic, Object msgContent) {
        if (StrUtil.isBlank(topic)) {
            topic = MASS_PREFIX + "/toAll";
        }
        clientCache.sendBroadcast(topic, msgContent);
        //socketIOServer.getBroadcastOperations().sendEvent(topic, msgContent);

    }

    @Override
    public void sendMessage(String eventName, String userId, Object msgContent) {
        MessageInfoStructure socketIOMessageDTO = MessageInfoStructure.builder().topic(eventName).userId(userId).msgContent(JSONUtil.toJsonStr(msgContent)).build();

        if (StrUtil.isNotBlank(userId)) {
            if (Objects.nonNull(serverProperties) && serverProperties.isCluster()) {
                RTopic rTopic = redissonClient.getTopic(TOPIC_SOCKETIO_SINGLE);
                rTopic.publish(socketIOMessageDTO);
            } else {
                pushMessageToUser(eventName, socketIOMessageDTO.getUserId(), msgContent);
            }
        } else {
            RTopic rTopic = redissonClient.getTopic(TOPIC_SOCKETIO_TOALL);
            rTopic.publish(socketIOMessageDTO);
            //sendToAll(eventName, msgContent);
        }
    }

    @PostConstruct
    public void init() {
        if (redissonClient == null) {
            return;
        }
        RTopic topic = redissonClient.getTopic(TOPIC_SOCKETIO_SINGLE);
        topic.addListener(MessageInfoStructure.class, (channel, msg) -> {

            if (StrUtil.isNotBlank(msg.getUserId())) {
                pushMessageToUser(msg.getTopic(), msg.getUserId(), JSONUtil.toBean(msg.getMsgContent(), Map.class));
                log.info(" {} {} {} {} {}", serverProperties.getPort(), channel.toString(), msg.getTopic(), msg.getUserId(), msg.getMsgContent());
            }
        });

        RTopic broadcast = redissonClient.getTopic(TOPIC_SOCKETIO_TOALL);
        broadcast.addListener(MessageInfoStructure.class, (channel, msg) -> {
            sendToAll(msg.getTopic(), JSONUtil.toBean(msg.getMsgContent(), Map.class));
            log.info(" sendToAll  {} {} {} {} {}", serverProperties.getPort(), channel.toString(), msg.getTopic(), msg.getUserId(), msg.getMsgContent());
        });
    }

}

到了这里,关于Spingboot 整合netty-socket.io的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java IO流(五)Netty实战[TCP|Http|心跳检测|Websocket]

    Java IO流(五)Netty实战[TCP|Http|心跳检测|Websocket]

    Server端  Client 运行结果 Server Client 运行结果  注意: 需要调整readerIdleTime|writerIdleTime|allIdleTime参数才会显示对应超时信息 服务端 客户端(浏览器) 效果图

    2024年02月11日
    浏览(13)
  • 使用Netty实现Socket网络编程

    ** ** Netty支持多种网络通信模型,包括传统的阻塞I/O、非阻塞I/O、多路复用I/O和异步I/O。其中,非阻塞I/O和多路复用I/O是Netty的核心特性。 非阻塞I/O :Netty通过使用Java的NIO(New I/O)库,实现了非阻塞的I/O操作。这意味着当一个操作正在进行时,不会阻塞线程,线程可以继续处

    2024年01月16日
    浏览(14)
  • 解决 java sdk 链接的 fisco bcos报错的终极指南Caused by: io.netty.channel.ChannelException: init channel network

    解决 java sdk 链接的 fisco bcos报错的终极指南Caused by: io.netty.channel.ChannelException: init channel network

    有好友询问了一个关于fisco bcos java sdk 链接的问题,记录一下,有遇到的朋友可以参考解决!

    2024年02月11日
    浏览(16)
  • Netty系列(一):Springboot整合Netty,自定义协议实现

    Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单

    2023年04月25日
    浏览(13)
  • SpringBoot搭建Netty+Socket+Tcp服务端和客户端

    yml配置:    完成,启动项目即可自动监听对应端口 这里为了测试,写了Main方法,可以参考服务端,配置启动类 ,实现跟随项目启动   ......想写就参考服务端...... 有测试的,,,但是忘记截图了................

    2024年02月15日
    浏览(17)
  • SpringBoot整合Netty

    SpringBoot整合Netty

    简介 Netty是一个基于Java的开源网络应用框架,它提供了高性能、异步事件驱动的网络编程能力。Netty旨在帮助开发者构建高性能、高可靠性的网络应用程序。 Netty提供了简洁的API和丰富的功能,可以轻松处理各种网络通信协议,如TCP、UDP、WebSocket等。它的设计理念是基于事件

    2024年02月08日
    浏览(10)
  • io.netty学习(二)Netty 架构设计

    io.netty学习(二)Netty 架构设计

    目录 前言 Selector 模型 SelectableChannel Channel 注册到 Selector SelectionKey 遍历 SelectionKey 事件驱动 Channel 回调 Future 事件及处理器 责任链模式 责任链模式的优缺点 ChannelPipeline 将事件传递给下一个处理器 总结 上一篇文章,我们对  Netty 做了一个基本的概述,知道什么是 Netty 以及

    2024年02月10日
    浏览(13)
  • springboot整合netty的正确姿势

    近期做一些物联网方面项目,使用到了tcp协议,之前公司做过socket短连接,网上找了一个简单的demo,很早便学习到nio方面知识,学习了《netty从入门到精通》这本书,同时也根据网上视频做了几个demo,但学习不太深入,刚好物联网项目,就直接使用netty,前期直接使用这个框

    2024年02月05日
    浏览(12)
  • Springboot整合Netty,自定义协议实现

    Springboot整合Netty,自定义协议实现

    新建springboot项目,并在项目以来中导入netty包,用fastjson包处理jsonStr。 创建netty相关配置信息文件 yml配置文件—— application.yml netty配置实体类—— NettyProperties 与yml配置文件绑定 通过 @ConfigurationProperties(prefix = \\\"netty\\\") 注解读取配置文件中的netty配置,通过反射注入值,需要在

    2024年02月06日
    浏览(12)
  • netty学习(3):SpringBoot整合netty实现多个客户端与服务器通信

    netty学习(3):SpringBoot整合netty实现多个客户端与服务器通信

    创建一个SpringBoot工程,然后创建三个子模块 整体工程目录:一个server服务(netty服务器),两个client服务(netty客户端) pom文件引入netty依赖,springboot依赖 NettySpringBootApplication NettyServiceHandler SocketInitializer NettyServer NettyStartListener application.yml Client1 NettyClientHandler SocketInitializ

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包