【问题标题】:Spring Integration and TCP server socket - how can I send a message to a client?Spring 集成和 TCP 服务器套接字 - 我如何向客户端发送消息?
【发布时间】:2014-09-25 22:45:23
【问题描述】:
我正在尝试在 Spring 中创建一个服务器,该服务器正在侦听 TCP 端口并接受连接。
我知道如何将传入请求路由到我的服务,并且它可以响应这些请求。
但是,我想在没有收到任何请求的情况下向某些客户发送消息。例如,有时我必须通知客户它收到了一条消息。
为此,我认为我需要一种方法来识别客户,例如通过让他们登录。有没有办法让每个活动连接都有一个“会话”对象,我可以在其中存储登录数据?
如何向使用用户名 X 登录的客户端发送消息?
这可能在 Spring 中实现吗?
【问题讨论】:
标签:
java
spring
sockets
tcp
spring-integration
【解决方案1】:
从 3.0 版开始;现在的框架emits connection events when there are connection state changes。您可以使用ApplicationListener 或<event:inbound-channel-adapter/> 捕获这些事件。
TcpConnectionOpenEvent 包含一个connectionId;一旦知道它的 ID,您就可以向任何连接发送任意消息,方法是在消息中填充 IpHeaders.connectionId 标头 (ip_connectionId) 并将其发送到 <tcp:outbound-channel-adapter/>。
如果您需要支持请求/回复以及发送任意消息,则需要使用一对协作的通道适配器进行所有通信,而不是网关。
编辑
这是一个简单的启动应用程序...
package com.example;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import javax.net.SocketFactory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.ip.IpHeaders;
import org.springframework.integration.ip.tcp.TcpReceivingChannelAdapter;
import org.springframework.integration.ip.tcp.TcpSendingMessageHandler;
import org.springframework.integration.ip.tcp.connection.TcpConnectionOpenEvent;
import org.springframework.integration.ip.tcp.connection.TcpNetServerConnectionFactory;
import org.springframework.integration.ip.tcp.connection.TcpServerConnectionFactory;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
@SpringBootApplication
public class So25102101Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = new SpringApplicationBuilder(So25102101Application.class)
.web(false)
.run(args);
int port = context.getBean(TcpServerConnectionFactory.class).getPort();
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = reader.readLine();
System.out.println(line);
context.close();
}
@Bean
public TcpReceivingChannelAdapter server(TcpNetServerConnectionFactory cf) {
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(cf);
adapter.setOutputChannel(inputChannel());
return adapter;
}
@Bean
public MessageChannel inputChannel() {
return new QueueChannel();
}
@Bean
public MessageChannel outputChannel() {
return new DirectChannel();
}
@Bean
public TcpNetServerConnectionFactory cf() {
return new TcpNetServerConnectionFactory(0);
}
@Bean
public IntegrationFlow outbound() {
return IntegrationFlows.from(outputChannel())
.handle(sender())
.get();
}
@Bean
public MessageHandler sender() {
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(cf());
return tcpSendingMessageHandler;
}
@Bean
public ApplicationListener<TcpConnectionOpenEvent> listener() {
return new ApplicationListener<TcpConnectionOpenEvent>() {
@Override
public void onApplicationEvent(TcpConnectionOpenEvent event) {
outputChannel().send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, event.getConnectionId())
.build());
}
};
}
}
pom 部门:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-ip</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>