- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试基于 Spring Websocket Demo 构建一个 websocket 消息传递应用程序运行 ActiveMQ作为 Undertow 的 STOMP 消息代理.该应用程序在不安全的连接上运行良好。但是,我在配置 STOMP Broker Relay 时遇到困难使用 SSL 连接转发。
如 Spring WebSocket 文档中所述...
The "STOMP broker relay" in the above configuration is a Spring MessageHandler that handles messages by forwarding them to an external message broker. To do so it establishes TCP connections to the broker, forwards all messages to it, and then forwards all messages received from the broker to clients through their WebSocket sessions. Essentially it acts as a "relay" that forwards messages in both directions.
此外,文档说明了对 reactor-net 的依赖性我有...
Please add a dependency on org.projectreactor:reactor-net for TCP connection management.
问题是我当前的实现没有初始化 NettyTCPClient通过 SSL,因此 ActiveMQ 连接失败并出现 SSLException。
[r.i.n.i.n.t.NettyTcpClient:307] » CONNECTED:
[id: 0xcfef39e9, /127.0.0.1:17779 => localhost/127.0.0.1:8442]
...
[o.a.a.b.TransportConnection.Transport:245] »
Transport Connection to: tcp://127.0.0.1:17779 failed:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
...
因此,我尝试研究 Project Reactor Docs为连接设置 SSL 选项,但我没有成功。
此时我找到了 StompBrokerRelayMessageHandler初始化 NettyTCPClient默认在 Reactor2TcpClient然而,它似乎不可配置。
如有帮助,我们将不胜感激。
中南合作商会
app.props
spring.activemq.in-memory=true
spring.activemq.pooled=false
spring.activemq.broker-url=stomp+ssl://localhost:8442
server.port=8443
server.ssl.enabled=true
server.ssl.protocol=tls
server.ssl.key-alias=undertow
server.ssl.key-store=classpath:undertow.jks
server.ssl.key-store-password=xxx
server.ssl.trust-store=classpath:undertow_certs.jks
server.ssl.trust-store-password=xxx
WebSocketConfig
//...
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
private static final Logger log = LoggerFactory.getLogger(WebSocketConfig.class);
private final static String KEYSTORE = "/activemq.jks";
private final static String KEYSTORE_PASS = "xxx";
private final static String KEYSTORE_TYPE = "JKS";
private final static String TRUSTSTORE = "/activemq_certs.jks";
private final static String TRUSTSTORE_PASS = "xxx";
private static String getBindLocation() {
return "stomp+ssl://localhost:8442?transport.needClientAuth=false";
}
@Bean(initMethod = "start", destroyMethod = "stop")
public SslBrokerService activeMQBroker() throws Exception {
final SslBrokerService service = new SslBrokerService();
service.setPersistent(false);
KeyManager[] km = SecurityManager.getKeyManager();
TrustManager[] tm = SecurityManager.getTrustManager();
service.addSslConnector(getBindLocation(), km, tm, null);
final ActiveMQTopic topic = new ActiveMQTopic("jms.topic.test");
service.setDestinations(new ActiveMQDestination[]{topic});
return service;
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/topic").setRelayHost("localhost").setRelayPort(8442);
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/welcome").withSockJS();
registry.addEndpoint("/test").withSockJS();
}
private static class SecurityManager {
//elided...
}
}
SOLVED Per Rossens Advice. Here's the implementation details for anyone interested.
WebSocketConfig
@Configuration
public class WebSocketConfig extends DelegatingWebSocketMessageBrokerConfiguration {
...
@Bean
public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler() {
StompBrokerRelayMessageHandler handler = (StompBrokerRelayMessageHandler) super.stompBrokerRelayMessageHandler();
ConfigurationReader reader = new StompClientDispatcherConfigReader();
Environment environment = new Environment(reader).assignErrorJournal();
TcpOperations<byte[]> client = new Reactor2TcpClient<>(new StompTcpClientSpecFactory(environment,"localhost", 8443));
handler.setTcpClient(client);
return handler;
}
}
StompTCPClientSpecFactory
private static class StompTcpClientSpecFactory
implements NetStreams.TcpClientFactory<Message<byte[]>, Message<byte[]>> {
private static final Logger log = LoggerFactory.getLogger(StompTcpClientSpecFactory.class);
private final String host;
private final int port;
private final String KEYSTORE = "src/main/resources/tcpclient.jks";
private final String KEYSTORE_PASS = "xxx";
private final String KEYSTORE_TYPE = "JKS";
private final String TRUSTSTORE = "/src/main/resources/tcpclient_certs.jks";
private final String TRUSTSTORE_PASS = "xxx";
private final String TRUSTSTORE_TYPE = "JKS";
private final Environment environment;
private final SecurityManager tcpManager = new SecurityManager
.SSLBuilder(KEYSTORE, KEYSTORE_PASS)
.keyStoreType(KEYSTORE_TYPE)
.trustStore(TRUSTSTORE, TRUSTSTORE_PASS)
.trustStoreType(TRUSTSTORE_TYPE)
.build();
public StompTcpClientSpecFactory(Environment environment, String host, int port) {
this.environment = environment;
this.host = host;
this.port = port;
}
@Override
public Spec.TcpClientSpec<Message<byte[]>, Message<byte[]>> apply(
Spec.TcpClientSpec<Message<byte[]>, Message<byte[]>> tcpClientSpec) {
return tcpClientSpec
.ssl(new SslOptions()
.sslProtocol("TLS")
.keystoreFile(tcpManager.getKeyStore())
.keystorePasswd(tcpManager.getKeyStorePass())
.trustManagers(tcpManager::getTrustManager)
.trustManagerPasswd(tcpManager.getTrustStorePass()))
.codec(new Reactor2StompCodec(new StompEncoder(), new StompDecoder()))
.env(this.environment)
.dispatcher(this.environment.getCachedDispatchers("StompClient").get())
.connect(this.host, this.port);
}
}
最佳答案
StompBrokerRelayMessageHandler
有一个可以设置的 tcpClient 属性。但是,我们似乎没有通过 WebSocketMessageBrokerConfigurer
设置公开它。
您可以删除 @EnableWebSocketMessageBroker
并改为扩展 DelegatingWebSocketMessageBrokerConfiguration
。它实际上是相同的,但您现在直接从提供所有 bean 的配置类进行扩展。
这允许您覆盖 stompBrokerRelayMessageHandler()
bean 并直接设置其 TcpClient 属性。只需确保重写方法用 @Bean
标记即可。
关于java - Spring Boot SSL TCPClient ~ StompBrokerRelayMessageHandler ~ ActiveMQ ~ Undertow,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34334629/
要关闭 TcpClient,必须关闭流。通常的做法是: client.GetStream().Close(); client.Close(); 因此仅使用 client
我正在阅读 the documentation on TcpClient.Close()并注意到这一点: Calling this method will eventually result in t
用于同步消息交换的我的客户端类: public class AsClient { private TcpClient connection; public AsClient(int s
我正在制作一个向许多 TCP 监听器发送数据的程序。如果不再使用其中一个 TCP 发送 channel ,我们是否需要使用 TCPClient.close 将其关闭。如果我们让它打开会怎样? 谢谢!
.NET 允许两种非常相似的方式从网络“读取”(假设 TCP 连接): 1. TcpClient.GetStream().Read() 2. TcpClient.Client.Receive() 通过
我找到了一些关于如何用 C# 编写 TCP/IP 客户端-服务器应用程序的代码服务器 Main 以此开头: TcpListener serverSocket = new TcpListener(888
我正在尝试连接到本地网络内的路由器。到目前为止,我已经使用了 TcpClient。 检查我的代码: public static void RouterConnect() {
服务器 : public class TcpServer { private TcpListener tcpListener; private static ManualResetEv
我想使用 TcpClient 发送 HTTP 请求。考虑以下代码: byte[] buf = new byte[1024]; string header = "GET
我在半关闭 TcpClient 时遇到了严重问题。我想做的是: 在客户端: 发送消息 关闭用于发送的底层套接字 收到回复 关闭用于读取的底层套接字(或者,此时,直接关闭它) 在服务器上: 接收消息 关
我有一个客户端和服务器,都有接收和发送方法,并且都使用相同的数据包类、数据包头大小和反序列化等。 如果我只发送较小的文本消息包,一切正常,但是当我尝试发送图像时,缓冲区溢出并且出现内存不足异常。奇怪的
在我的 C# 应用程序中,我有一个线程,它基本上不断地从 TcpClient 读取数据,直到被告知停止。为此,我使用 WaitHandles,例如: private ManualResetEvent
我有一个客户端-服务器程序。 我正在发送这样的数据: private void Sender(string s,TcpClient sock) { try { byte[] b
这个问题在这里已经有了答案: C# network connection running from shared drive (1 个回答) 关闭 7 年前。 我几天前问过类似的问题。那时,我正在尝
我有一个 TCPClient,它创建一个流,当 DataAvailable 时我从中读取流。 每 20 秒 !DataAvailable 我会使用 ACK 消息对套接字执行 ping 操作,以防止流关
我正在使用 SwifSockets:https://github.com/swiftsocket/SwiftSocket :按照有关如何使用它的说明后,我在堆栈溢出上找到了此代码:Sending Me
我在继承的一些代码中有一个奇怪的行为 - 下面的简化示例演示了如果内置到普通控制台应用程序中的问题。 WhoIs 在第 5 次调用时达到其使用限额 - 并返回一条消息 + 关闭套接字。使用 ReadL
我正在用 C# 开发一个 Tcp 客户端,我正在使用 TcpClient 类。我无法连接到服务器。 调试应用程序我可以看到对 Connect 的调用是成功的,但是在我这样做之后,我用 netstat
我有一个我似乎无法弄清楚的问题,请帮忙。我创建了一个类来处理使用 TcpClient 的某些硬件的接口(interface)。我希望此类在 HW 被销毁之前向 HW 发送最后一个命令。 为了解决这个问
您好,感谢您的帮助。这次想问一下TcpClient。我有一个服务器程序,我正在编写一个客户端程序。此客户端使用 TcpClient。首先是创建一个新客户端 clientSocket=new TcpCl
我是一名优秀的程序员,十分优秀!