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 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

View File

@ -224,7 +224,7 @@ class PlayConnection(
renderLatch.awaitWithChange()
}
Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.INFO) { "Connecting to server: $address" }
network.connect(address)
network.connect(address, profiles.other.epoll)
state = PlayConnectionStates.ESTABLISHING
} catch (exception: Throwable) {
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)" }
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
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.minosoft.config.profile.profiles.other.OtherProfileManager
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.ChannelFuture
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.socket.nio.NioSocketChannel
import javax.crypto.Cipher
@ -69,12 +72,19 @@ class NettyClient(
private set
private var channel: Channel? = null
fun connect(address: ServerAddress) {
val workerGroup = NioEventLoopGroup(DefaultThreadPool.threadCount - 1, DefaultThreadPool)
// val workerGroup = NioEventLoopGroup()
fun connect(address: ServerAddress, epoll: Boolean) {
val threadPool: EventLoopGroup
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()
.group(workerGroup)
.channel(NioSocketChannel::class.java)
.group(threadPool)
.channel(channelClass)
.handler(NetworkPipeline(this))
val future: ChannelFuture = bootstrap.connect(address.hostname, address.port).sync()
@ -85,9 +95,11 @@ class NettyClient(
}
val channel = future.channel()
this.channel = channel
channel.config().setOption(ChannelOption.TCP_NODELAY, true)
try {
channel.config().setOption(ChannelOption.TCP_NODELAY, true)
} catch (_: Throwable) {
}
connected = true
println("Connected!")
}
}
@ -103,7 +115,6 @@ class NettyClient(
fun disconnect() {
channel?.close()
// ToDo: workerGroup.shutdownGracefully()
connected = false
}
@ -119,4 +130,9 @@ class NettyClient(
packet.log((connection.nullCast<PlayConnection>()?.profiles?.other ?: OtherProfileManager.selected).log.reducedProtocolLog)
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")) }
}
}