Spring boot 如何配置仅连接客户端和发送消息的服务器的spring集成适配器

Spring boot 如何配置仅连接客户端和发送消息的服务器的spring集成适配器,spring-boot,tcp,spring-integration,Spring Boot,Tcp,Spring Integration,我尝试使用Spring集成实现以下场景: 我需要一个客户端通过TCP IP连接到服务器,并在30秒内等待接收消息。 我需要一个服务器向已连接的客户端发送0到n条消息。 我需要一种在不丢失消息的情况下启动和停止通道传输的方法。 我需要在停止和启动之间更改服务器正在侦听的端口 这是我目前的配置: @Configuration public class TcpConfiguration { private static Logger LOG = LoggerFactory.getLogger(

我尝试使用Spring集成实现以下场景:

我需要一个客户端通过TCP IP连接到服务器,并在30秒内等待接收消息。 我需要一个服务器向已连接的客户端发送0到n条消息。 我需要一种在不丢失消息的情况下启动和停止通道传输的方法。 我需要在停止和启动之间更改服务器正在侦听的端口

这是我目前的配置:

@Configuration
public class TcpConfiguration {
    private static Logger LOG = LoggerFactory.getLogger(TcpConfiguration.class);

    @Value("${port}")
    private Integer port;

    @Value("${so-timeout}")
    private Integer soTimeout;

    @Value("${keep-alive}")
    private Boolean keepAlive;

    @Value("${send-timeout}")
    private Integer sendTimeout;

    @Bean
    public AbstractServerConnectionFactory getMyConnFactory() {
        LOG.debug("getMyConnFactory");
        TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
        LOG.debug("getMyConnFactory port={}", port);
        factory.setSoTimeout(soTimeout);
        LOG.debug("getMyConnFactory soTimeout={}", soTimeout);
        factory.setSoKeepAlive(true);
        LOG.debug("getMyConnFactory keepAlive={}", keepAlive);
        return factory;
    }

    @Bean
    public AbstractEndpoint getMyChannelAdapter() {
        LOG.debug("getMyChannelAdapter");
        TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
        adapter.setConnectionFactory(getMyConnFactory());
        adapter.setOutputChannel(myChannelIn());
        adapter.setSendTimeout(sendTimeout);
        LOG.debug("getMyChannelAdapter adapter={}", adapter.getClass().getName());
        return adapter;
    }

    @Bean
    public MessageChannel myChannelIn() {
        LOG.debug("myChannelIn");
        return new DirectChannel();
    }

    @Bean
    @Transformer(inputChannel = "myChannelIn", outputChannel = "myServiceChannel")
    public ObjectToStringTransformer myTransformer() {
        LOG.debug("myTransformer");
        return new ObjectToStringTransformer();
    }

    @ServiceActivator(inputChannel = "myServiceChannel")
    public void service(String in) {
        LOG.debug("service received={}", in);
    }

    @Bean
    public MessageChannel myChannelOut() {
        LOG.debug("myChannelOut");
        return new DirectChannel();
    }

    @Bean
    public IntegrationFlow myOutbound() {
        LOG.debug("myOutbound");
        return IntegrationFlows.from(myChannelOut())
                .handle(mySender())
                .get();
    }

    @Bean
    public MessageHandler mySender() {
        LOG.debug("mySender");
        TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
        tcpSendingMessageHandler.setConnectionFactory(getMyConnFactory());
        return tcpSendingMessageHandler;
    }
}
请指教

要更改服务器端口,我将关闭应用程序上下文,并在远程配置服务器中配置新端口后重新启动它。 我可以在不破坏当前消息传输的情况下关闭应用程序上下文吗? 我不知道如何处理仅连接客户端的事情。

使用;只需获取连接即可打开它,而无需发送

@springboot应用程序
公共类SO62867670应用程序{
公共静态void main(字符串[]args){
SpringApplication.run(So62867670Application.class,args);
}
@豆子
公共应用程序运行程序(DynamicCpReceiver接收器){
返回args->{//只是一个演示,显示开始/停止
接收器。连接并监听(1234);
System.in.read();
接收器。停止();
System.in.read();
接收器。连接并监听(1235);
System.in.read();
接收器。停止();
};
}
}
@组成部分
类动态cReceiver{
@自动连线
私有集成流上下文;
私人综合流动登记;
public void connectAndListen(int端口)引发中断异常{
TcpClientConnectionFactorySpec client=Tcp.netClient(“本地主机”,端口)
.deserializer(TcpCodecs.lf());
IntegrationFlow=IntegrationFlows.from(Tcp.inboundAdapter(客户端))
.transform(Transformers.objectToString())
.handle(System.out::println)
.get();
this.registration=context.registration(flow.register();
client.get().getConnection();//只需打开单个共享连接
}
公共停车场(){
if(this.registration!=null){
这个.registration.destroy();
this.registration=null;
}
}
}
编辑

这是服务器端

@springboot应用程序
@使能调度
公共类So62867670ServerApplication{
公共静态void main(字符串[]args){
run(So62867670ServerApplication.class,args);
}
@豆子
公共应用程序运行程序(DynamicTcpServer接收器){
返回args->{//只是一个演示,显示开始/停止
接收人:tcpListen(1234);
System.in.read();
接收器。停止(1234);
System.in.read();
接收人:tcpListen(1235);
System.in.read();
接收器。停止(1235);
};
}
}
@组成部分
类动态Cpserver{
私有静态最终记录器LOG=LoggerFactory.getLogger(dynamictcserver.class);
@自动连线
私有集成流上下文流上下文;
@自动连线
私有应用上下文appContext;
私有最终映射注册=新HashMap();
私有最终映射客户端=新ConcurrentHashMap();
公共无效tcpListen(内部端口){
TcpServerConnectionFactorySpec服务器=Tcp.netServer(端口)
.id(“服务器-”+端口)
.serializer(TcpCodecs.lf());
server.get().registerListener(msg->false);//虚拟侦听器,因此接受线程不会退出
IntegrationFlow=f->f.handle(Tcp.outboundAdapter(服务器));
this.registrations.put(端口,flowContext.registration(flow.register());
}
公共空站(内部端口){
IntegrationFlowRegistration=this.registrations.remove(端口);
if(注册!=null){
注册。销毁();
}
}
@事件监听器
公共无效关闭(TcpConnectionOpenEvent事件){
LOG.info(event.toString());
字符串connectionId=event.getConnectionId();
String[]split=connectionId.split(“:”);
int port=Integer.parseInt(拆分[2]);
this.clients.put(connectionId,new AbstractMap.SimpleEntry(port,new AtomicInteger());
}
@事件监听器
公共无效关闭(TcpConnectionCloseEvent事件){
LOG.info(event.toString());
this.clients.remove(event.getConnectionId());
}
@事件监听器
公共无效侦听(TCPConnectionServerListingEvent事件){
LOG.info(event.toString());
}
@计划(固定延迟=5000)
公共无效发送者(){
this.clients.forEach((connectionId,portAndCount)->{
IntegrationFlowRegistration=this.registrations.get(portAndCount.getKey());
if(注册!=null){
日志信息(“发送到”+连接ID);
registration.getMessagingTemplate().send(MessageBuilder.withPayload(“foo”)
.setHeader(IpHeaders.CONNECTION_ID,connectionId).build());
如果(portAndCount.getValue().incrementAndGet()>9){
this.appContext.getBean(“服务器-”+portAndCount.getKey(),TcpNetServerConnectionFactory.class)
.紧密连接(连接ID);
}
}
});
}
}

非常感谢Gary!需要一些时间来检查它。我在侦听模式下使用了
netcat
nc
,在Mac上)来测试它-因此使用了linefeed反序列化器
nc-l 1234
在一个终端中,而
nc-l 1235
在另一个终端中。我有点麻烦,无法将代码包含在runner方法中以接收任何内容。但主要是我无法明确我的重点放在服务器端。Gary,你有没有另一段代码让服务器重新启动