java - 在同一个 Spring Boot 应用程序中使用 Tomcat HTTP 和 Netty UDP
问题描述
我正在编写一个需要能够侦听 UDP 数据报并公开一些 HTTP 端点的应用程序。
我将 Spring Boot 与 Web Starter 用于 HTTP 部分,将 Netty 用于 UDP。
要设置 UDP,我使用以下代码:
@Configuration
class NettyConfig(
@Value("\${netty.port}")
val port: Int,
@Value("\${netty.epoll}")
val epoll: Boolean
) {
val log = LoggerFactory.getLogger(NettyConfig::class.java)!!
@Bean
fun executor() = Executors.newFixedThreadPool(threads)!!
@Bean
fun bootstrap(handlerService: HandlerService): Bootstrap {
val master: EventLoopGroup
val clazz: Class<out Channel>
log.info("Starting Netty Server. EPoll enable: $epoll")
if (epoll) {
master = EpollEventLoopGroup(1)
clazz = EpollDatagramChannel::class.java
} else {
master = NioEventLoopGroup(1)
clazz = NioDatagramChannel::class.java
}
val bootstrap = Bootstrap()
.group(master)
.channel(clazz)
.option(ChannelOption.SO_SNDBUF, 1048576)
.option(ChannelOption.SO_RCVBUF, 1048576)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator(2048, 2048, 64 * 2048))
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.option(ChannelOption.SO_BROADCAST, true)
.handler(object: ChannelInitializer<DatagramChannel>() {
override fun initChannel(ch: DatagramChannel) {
ch.pipeline().addLast(
LineBasedFrameDecoder(1048576),
handler(handlerService))
}
})
val channel = bootstrap.bind(port).sync().channel()
log.info("Started Netty Server. Listening on {}", port)
channel.closeFuture().sync()
log.info("Stopped Netty Server.")
return bootstrap
}
...
而一个 HTTP 部分由 Spring Starter Web 管理,由 Tomcat 实现。
我想要达到的目标:
- 应用程序侦听给定端口(例如 5432)上的 UDP 事件
- 应用程序在 8080 端口上侦听 HTTP 请求
- 应用程序实现它自己的 HTTP API
- 应用程序通过 HTTP 公开执行器端点以管理/监视它
两个部分都在工作,但不能一起工作。通过反复试验,我遇到了以下问题:如果我注释掉这一行(即不启动 Netty):
val channel = bootstrap.bind(port).sync().channel()
HTTP 部分有效(而 UDP obv. 无效)。如果我把它留在原地 - 一切都开始了,但是,任何对 8080 端口的请求都会给出连接被拒绝的错误。
据我了解应该没有问题,因为两台服务器都在监听不同的端口(5432 vs 8080),这就是我在日志消息中得到的。所以两台服务器之间有一些重要的交互,我不知道。
我该如何解决它,以便两台服务器将在同一个 JVM/Spring Boot 应用程序中一起运行?
解决方案
我怀疑您的应用程序由于方法而没有完成channel.closeFuture().sync()
启动bootstrap
@Bean
。由于启动未完成,Tomcat 没有机会启动,因此它无法接受任何传入连接。
与其阻止 bean 的创建,不如使用 destroy 方法channel.closeFuture().sync()
作为应用程序上下文关闭处理的一部分进行调用。为此,您可以DisposibleBean
使用@PreDestroy
.
推荐阅读
- haskell - 在预定义的访问者模式迭代器中提取/累积结果的“Haskell 方式”
- node.js - Ghostscript PDF TO Image 转换日志消息
- flask - 在 Flask Web App 中刷新 Salesforce 访问令牌
- visual-studio - 在另一个 IDE 中构建 C++ Visual Studio 项目:致命错误 afxwin.h
- git - git push 返回缺少或无效的凭据。代码:'ECONNREFUSED',远程:找不到存储库
- reactjs - 我如何重构这个 if 语句?(反应)
- javascript - Strapi 上传的文件未显示在网站上
- javascript - 为什么我不能通过 javascript 创建标签
- git - 当没有为远程存储库设置 ssh 公钥/私钥时,避免 git 的密码提示
- python - 如何将编码文本转换为正文(没有编码创建的特殊字符)