Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java spring tcp套接字,授权客户端并处理挂起的响应_Java_Spring_Sockets_Tcp_Spring Integration - Fatal编程技术网

Java spring tcp套接字,授权客户端并处理挂起的响应

Java spring tcp套接字,授权客户端并处理挂起的响应,java,spring,sockets,tcp,spring-integration,Java,Spring,Sockets,Tcp,Spring Integration,Spring框架也支持tcp连接,我写了下面的代码来设置一个简单的套接字服务器,我不知道如何将下面的未来添加到我的套接字服务器: 基于唯一标识符授权客户端(例如,从客户端接收的客户端机密,可能使用) 直接向特定客户端发送消息(基于标识符) 广播消息 更新: Config.sendMessage添加以向单个客户端发送消息 Config.broadCast已添加到广播消息中 authorizeIncomingConnection要授权客户端,请接受或拒绝连接 tcpConnections添加静

Spring框架也支持tcp连接,我写了下面的代码来设置一个简单的套接字服务器,我不知道如何将下面的未来添加到我的套接字服务器:

  • 基于唯一标识符授权客户端(例如,从客户端接收的客户端机密,可能使用)
  • 直接向特定客户端发送消息(基于标识符)
  • 广播消息
更新:

  • Config.sendMessage
    添加以向单个客户端发送消息

  • Config.broadCast
    已添加到广播消息中

  • authorizeIncomingConnection
    要授权客户端,请接受或拒绝连接

  • tcpConnections
    添加静态字段以保留tcpEvent源

问题

  • 使用
    tcpConnections
    HashMap好主意吗

  • 我实施的授权方法好吗

Main.java

@SpringBootApplication
public class Main {

    public static void main(final String[] args) {
        SpringApplication.run(Main.class, args);
    }

}
Config.java

@EnableIntegration
@IntegrationComponentScan
@Configuration
public class Config implements ApplicationListener<TcpConnectionEvent> {

    private static final Logger LOGGER = Logger.getLogger(Config.class.getName());

    @Bean
    public AbstractServerConnectionFactory AbstractServerConnectionFactory() {
        return new TcpNetServerConnectionFactory(8181);
    }

    @Bean
    public TcpInboundGateway TcpInboundGateway(AbstractServerConnectionFactory connectionFactory) {
        TcpInboundGateway inGate = new TcpInboundGateway();
        inGate.setConnectionFactory(connectionFactory);
        inGate.setRequestChannel(getMessageChannel());
        return inGate;
    }

    @Bean
    public MessageChannel getMessageChannel() {
        return new DirectChannel();
    }

    @MessageEndpoint
    public class Echo {

        @Transformer(inputChannel = "getMessageChannel")
        public String convert(byte[] bytes) throws Exception {
            return new String(bytes);
        }

    }

    private static ConcurrentHashMap<String, TcpConnection> tcpConnections = new ConcurrentHashMap<>();

    @Override
    public void onApplicationEvent(TcpConnectionEvent tcpEvent) {
        TcpConnection source = (TcpConnection) tcpEvent.getSource();
        if (tcpEvent instanceof TcpConnectionOpenEvent) {

            LOGGER.info("Socket Opened " + source.getConnectionId());
            tcpConnections.put(tcpEvent.getConnectionId(), source);

            if (!authorizeIncomingConnection(source.getSocketInfo())) {
                LOGGER.warn("Socket Rejected " + source.getConnectionId());
                source.close();
            }

        } else if (tcpEvent instanceof TcpConnectionCloseEvent) {
            LOGGER.info("Socket Closed " + source.getConnectionId());
            tcpConnections.remove(source.getConnectionId());
        }
    }

    private boolean authorizeIncomingConnection(SocketInfo socketInfo) {
        //Authorization Logic , Like Ip,Mac Address WhiteList or anyThing else !
        return (System.currentTimeMillis() / 1000) % 2 == 0;
    }

    public static String broadCast(String message) {
        Set<String> connectionIds = tcpConnections.keySet();
        int successCounter = 0;
        int FailureCounter = 0;
        for (String connectionId : connectionIds) {
            try {
                sendMessage(connectionId, message);
                successCounter++;
            } catch (Exception e) {
                FailureCounter++;
            }
        }
        return "BroadCast Result , Success : " + successCounter + " Failure : " + FailureCounter;
    }

    public static void sendMessage(String connectionId, final String message) throws Exception {
        tcpConnections.get(connectionId).send(new Message<String>() {
            @Override
            public String getPayload() {
                return message;
            }

            @Override
            public MessageHeaders getHeaders() {
                return null;
            }
        });
    }
}
用法:

  • 套接字请求/响应模式
  • 通知单一客户

    http://localhost:8080/notify/{connectionId}/{message}

  • 广播

    http://localhost:8080/broadCast/{message}


  • TcpConnectionOpenEvent
    包含一个
    connectionId
    属性。来自该客户端的每条消息都将在
    IpHeaders.CONNECTION\u ID
    消息头中具有相同的属性

  • 添加一个自定义路由器,跟踪每个连接的登录状态
  • 查找连接id,如果未经过身份验证,则路由到质询/响应子流
  • 经过身份验证后,路由到正常流
  • 要使用任意消息传递(而不是请求/响应),请使用
    tcprevivingchanneladapter
    TcpSendingMessageHandler
    而不是入站网关。两者都配置为使用相同的连接工厂。对于发送到消息处理程序的每条消息,将
    IpHeaders.CONNECTION\u ID
    头添加到特定客户端


    要广播,请为每个连接id发送一条消息。

    谢谢,我更新了我的问题,你能看一下吗?有趣的技术;哈希映射很好(尽管您应该在
    sendMessage
    中检查
    null
    ,因为存在竞争条件)。但是,您不能在发布连接打开事件的线程上进行身份验证,该线程是“接受”线程(服务器套接字)。数据将在不同的线程上发送。这就是为什么我说你需要一个路由器来通过身份验证逻辑路由套接字上的第一个请求。你能详细解释一下或者给我一个关于使用路由器的代码片段吗?如果尚未通过身份验证,请添加一个
    @router
    路由到身份验证逻辑。你也可以使用拦截器。请看和。再次感谢,我尝试了两种方法,当我们使用路由器或侦听器套接字服务器等待客户端的第一个请求来启动身份验证过程时,但若客户端从未发送任何请求呢,也许身份验证超时可以解决这个问题。在WebSocket中,我们可以发送握手参数(如查询字符串参数),以便服务器根据握手参数对客户端进行身份验证,或在接受之前拒绝连接,我们可以在tcp套接字中执行同样的操作吗?
    @Controller
    public class MainController {
    
        @RequestMapping("/notify/{connectionId}/{message}")
        @ResponseBody
        public String home(@PathVariable String connectionId, @PathVariable String message) {
            try {
                Config.sendMessage(connectionId, message);
                return "Client Notified !";
            } catch (Exception e) {
                return "Failed To Notify Client , cause : \n " + e.toString();
            }
        }
    
    
        @RequestMapping("/broadCast/{message}")
        @ResponseBody
        public String home(@PathVariable String message) {
            return Config.broadCast(message);
        }
    
    }