netty: use epoll when available, improvements

This commit is contained in:
Bixilon 2022-01-09 23:23:14 +01:00
parent 856eb050b4
commit eec979c664
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 59 additions and 11 deletions

View File

@ -35,6 +35,11 @@ class OtherProfile(
override val version: Int = latestVersion override val version: Int = latestVersion
override var description by delegate(description ?: "") override var description by delegate(description ?: "")
/**
* Use native network transport if available
*/
var epoll by delegate(true)
/** /**
* MacOS only: Ignores the warning if the jvm argument * MacOS only: Ignores the warning if the jvm argument

View File

@ -224,7 +224,7 @@ class PlayConnection(
renderLatch.awaitWithChange() renderLatch.awaitWithChange()
} }
Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.INFO) { "Connecting to server: $address" } Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.INFO) { "Connecting to server: $address" }
network.connect(address) network.connect(address, profiles.other.epoll)
state = PlayConnectionStates.ESTABLISHING state = PlayConnectionStates.ESTABLISHING
} catch (exception: Throwable) { } catch (exception: Throwable) {
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.FATAL) { exception } Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.FATAL) { exception }

View File

@ -143,7 +143,7 @@ class StatusConnection(
Log.log(LogMessageType.NETWORK_RESOLVING) { "Trying to ping $tryAddress (from $address)" } Log.log(LogMessageType.NETWORK_RESOLVING) { "Trying to ping $tryAddress (from $address)" }
state = StatusConnectionStates.ESTABLISHING state = StatusConnectionStates.ESTABLISHING
network.connect(tryAddress) network.connect(tryAddress, false)
} }
} }

View File

@ -0,0 +1,27 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.network.network.client
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicInteger
class NamedThreadFactory(
val format: String,
) : ThreadFactory {
var count = AtomicInteger(0)
override fun newThread(runnable: Runnable): Thread {
return Thread(runnable, format.format(count.incrementAndGet()))
}
}

View File

@ -14,7 +14,6 @@
package de.bixilon.minosoft.protocol.network.network.client package de.bixilon.minosoft.protocol.network.network.client
import de.bixilon.kutil.cast.CastUtil.nullCast import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.watcher.DataWatcher.Companion.watched import de.bixilon.kutil.watcher.DataWatcher.Companion.watched
import de.bixilon.minosoft.config.profile.profiles.other.OtherProfileManager import de.bixilon.minosoft.config.profile.profiles.other.OtherProfileManager
import de.bixilon.minosoft.protocol.network.connection.Connection import de.bixilon.minosoft.protocol.network.connection.Connection
@ -32,6 +31,10 @@ import io.netty.bootstrap.Bootstrap
import io.netty.channel.Channel import io.netty.channel.Channel
import io.netty.channel.ChannelFuture import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.netty.channel.EventLoopGroup
import io.netty.channel.epoll.Epoll
import io.netty.channel.epoll.EpollEventLoopGroup
import io.netty.channel.epoll.EpollSocketChannel
import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel import io.netty.channel.socket.nio.NioSocketChannel
import javax.crypto.Cipher import javax.crypto.Cipher
@ -69,12 +72,19 @@ class NettyClient(
private set private set
private var channel: Channel? = null private var channel: Channel? = null
fun connect(address: ServerAddress) { fun connect(address: ServerAddress, epoll: Boolean) {
val workerGroup = NioEventLoopGroup(DefaultThreadPool.threadCount - 1, DefaultThreadPool) val threadPool: EventLoopGroup
// val workerGroup = NioEventLoopGroup() val channelClass: Class<out Channel>
if (Epoll.isAvailable() && epoll) {
threadPool = EPOLL_THREAD_POOL
channelClass = EpollSocketChannel::class.java
} else {
threadPool = NIO_THREAD_POOL
channelClass = NioSocketChannel::class.java
}
val bootstrap = Bootstrap() val bootstrap = Bootstrap()
.group(workerGroup) .group(threadPool)
.channel(NioSocketChannel::class.java) .channel(channelClass)
.handler(NetworkPipeline(this)) .handler(NetworkPipeline(this))
val future: ChannelFuture = bootstrap.connect(address.hostname, address.port).sync() val future: ChannelFuture = bootstrap.connect(address.hostname, address.port).sync()
@ -85,9 +95,11 @@ class NettyClient(
} }
val channel = future.channel() val channel = future.channel()
this.channel = channel this.channel = channel
channel.config().setOption(ChannelOption.TCP_NODELAY, true) try {
channel.config().setOption(ChannelOption.TCP_NODELAY, true)
} catch (_: Throwable) {
}
connected = true connected = true
println("Connected!")
} }
} }
@ -103,7 +115,6 @@ class NettyClient(
fun disconnect() { fun disconnect() {
channel?.close() channel?.close()
// ToDo: workerGroup.shutdownGracefully()
connected = false connected = false
} }
@ -119,4 +130,9 @@ class NettyClient(
packet.log((connection.nullCast<PlayConnection>()?.profiles?.other ?: OtherProfileManager.selected).log.reducedProtocolLog) packet.log((connection.nullCast<PlayConnection>()?.profiles?.other ?: OtherProfileManager.selected).log.reducedProtocolLog)
channel.writeAndFlush(packet) channel.writeAndFlush(packet)
} }
companion object {
private val NIO_THREAD_POOL by lazy { NioEventLoopGroup(NamedThreadFactory("Nio#%d")) }
private val EPOLL_THREAD_POOL by lazy { EpollEventLoopGroup(NamedThreadFactory("Epoll#%d")) }
}
} }