Android:蜂窝网络对Wi-Fi连接Socket read_buffer_size的影响排查
排查Android应用与GoPro Wi-Fi传输在蜂窝网络环境下的不稳定问题
我正在排查Android应用与GoPro之间的Wi-Fi传输在不同蜂窝网络环境下表现不稳定的问题。最初发现GoPro官方应用Quik即使在2G网络下也能高效传输数据,但我的应用却做不到。研究其源码后发现,Quik将OkHttp的read_buffer_size覆盖设置为512kb,而非OkHttp根据蜂窝网络质量自动选择的值。在我的应用中做同样调整后,2G网络下的传输表现得到了改善。
但该解决方案并不完美:有时即使在4G网络下,传输速度也会变慢,且发现Quik在这些场景下同样会出现传输缓慢的情况。有趣的是,关闭蜂窝连接后传输速度会显著提升,这表明蜂窝网络与Wi-Fi网络之间可能存在交互影响性能。我正在寻找记录buffer大小的方法以进一步排查,同时探索Android或底层Linux内核对此行为的影响机制。
若您有相关建议、理论,或能指出蜂窝网络质量具体的影响点,我将不胜感激。
以下是我创建自定义Socket Factory以覆盖read_buffer_size的OkHttp客户端代码:
class CustomBufferSocketFactory( private val sendBufferSizeBytes: Int, private val receiveBufferSizeBytes: Int, private val tcpNoDelayEnabled: Boolean = false, private val socketFactory: SocketFactory = SocketFactory.getDefault() ) : SocketFactory() { override fun createSocket(): Socket { return configureSocket(socketFactory.createSocket()) } override fun createSocket(host: String, port: Int): Socket { return configureSocket(socketFactory.createSocket(host, port)) } override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket { return configureSocket(socketFactory.createSocket(host, port, localHost, localPort)) } override fun createSocket(address: InetAddress, port: Int): Socket { return configureSocket(socketFactory.createSocket(address, port)) } override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket { return configureSocket(socketFactory.createSocket(address, port, localAddress, localPort)) } private fun configureSocket(socket: Socket): Socket { socket.sendBufferSize = sendBufferSizeBytes socket.receiveBufferSize = receiveBufferSizeBytes socket.tcpNoDelay = tcpNoDelayEnabled return socket } } suspend fun connectToLocalNetwork( context: Context, ssid: String, password: String ): OkHttpClient? { return withTimeoutOrNull(15000L) { // Timeout after 15 seconds suspendCancellableCoroutine { continuation -> var isResumed = false val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager // Use WifiNetworkSpecifier to build a request for the desired Wi-Fi network val wifiSpecifier = WifiNetworkSpecifier.Builder() .setSsid(ssid) .setWpa2Passphrase(password) .build() // Build the network request val networkRequest = NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .removeTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) .setNetworkSpecifier(wifiSpecifier) .build() // Define the network callback val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { if (!isResumed && !continuation.isCancelled) { isResumed = true // Bind your app's network traffic to the specific network connectivityManager.bindProcessToNetwork(network) Logger.getLogger(OkHttpClient::class.java.name).setLevel(Level.FINE) // Use OkHttpClientFactory for large file downloads val client = OkHttpClient.Builder() .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .socketFactory(CustomBufferSocketFactory( 524288, 524288, true, network.socketFactory)) .build() continuation.resume(client) } } override fun onUnavailable() { if (!isResumed && !continuation.isCancelled) { isResumed = true continuation.resume(null) } } override fun onLost(network: Network) { if (!isResumed && !continuation.isCancelled) { isResumed = true continuation.resume(null) } } } connectivityManager.requestNetwork(networkRequest, networkCallback) } } }
内容的提问来源于stack exchange,提问作者Pavlo Sharhan
相关产品推荐
相关产品推荐

