I’m experiencing an issue with binding a DatagramSocket to a specific port (40000). Despite my efforts, Wireshark shows that packets are being sent from a different source port. Here is the relevant part of my ConnectDeviceViewModel code:
<code>import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.s2000mobile.Device
import com.example.s2000mobile.UdpClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.DatagramSocket
import java.net.InetSocketAddress
import java.net.SocketException
class ConnectDeviceViewModel : ViewModel() {
private val _devices = MutableStateFlow(emptyList<Device>())
val devices: StateFlow<List<Device>> = _devices
private val _ipAddress = MutableStateFlow("192.168.0.211")
val ipAddress: StateFlow<String> = _ipAddress
private val _port = MutableStateFlow(40000)
val port: StateFlow<Int> = _port
private val _timeout = MutableStateFlow(500)
val timeout: StateFlow<Int> = _timeout
private val _isSearching = MutableStateFlow(false)
val isSearching: StateFlow<Boolean> = _isSearching
fun updateIpAddress(newIpAddress: String) {
_ipAddress.value = newIpAddress
}
fun updatePort(newPort: Int) {
_port.value = newPort
}
fun updateTimeout(newTimeout: Int) {
_timeout.value = newTimeout
}
private var searchingProcess: Job? = null
private val udpClient = UdpClient()
fun findDevices() {
if (_isSearching.value) {
searchingProcess?.cancel()
_isSearching.value = false
return
}
searchingProcess = viewModelScope.launch {
_isSearching.value = true
var socket: DatagramSocket? = null
try {
withContext(Dispatchers.IO) {
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
for (slaveAddress in 1..247) {
if (!isActive) break
val data = ByteArray(4)
udpClient.sendPacket(
socket!!,
ipAddress.value,
port.value,
data
)
val response = udpClient.recievePacket(socket!!, timeout.value)
if (response != null) {
_devices.value = _devices.value + Device(slaveAddress, "КДЛ")
}
}
}
} finally {
socket?.close()
_isSearching.value = false
}
}
}
}
</code>
<code>import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.s2000mobile.Device
import com.example.s2000mobile.UdpClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.DatagramSocket
import java.net.InetSocketAddress
import java.net.SocketException
class ConnectDeviceViewModel : ViewModel() {
private val _devices = MutableStateFlow(emptyList<Device>())
val devices: StateFlow<List<Device>> = _devices
private val _ipAddress = MutableStateFlow("192.168.0.211")
val ipAddress: StateFlow<String> = _ipAddress
private val _port = MutableStateFlow(40000)
val port: StateFlow<Int> = _port
private val _timeout = MutableStateFlow(500)
val timeout: StateFlow<Int> = _timeout
private val _isSearching = MutableStateFlow(false)
val isSearching: StateFlow<Boolean> = _isSearching
fun updateIpAddress(newIpAddress: String) {
_ipAddress.value = newIpAddress
}
fun updatePort(newPort: Int) {
_port.value = newPort
}
fun updateTimeout(newTimeout: Int) {
_timeout.value = newTimeout
}
private var searchingProcess: Job? = null
private val udpClient = UdpClient()
fun findDevices() {
if (_isSearching.value) {
searchingProcess?.cancel()
_isSearching.value = false
return
}
searchingProcess = viewModelScope.launch {
_isSearching.value = true
var socket: DatagramSocket? = null
try {
withContext(Dispatchers.IO) {
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
for (slaveAddress in 1..247) {
if (!isActive) break
val data = ByteArray(4)
udpClient.sendPacket(
socket!!,
ipAddress.value,
port.value,
data
)
val response = udpClient.recievePacket(socket!!, timeout.value)
if (response != null) {
_devices.value = _devices.value + Device(slaveAddress, "КДЛ")
}
}
}
} finally {
socket?.close()
_isSearching.value = false
}
}
}
}
</code>
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.s2000mobile.Device
import com.example.s2000mobile.UdpClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.DatagramSocket
import java.net.InetSocketAddress
import java.net.SocketException
class ConnectDeviceViewModel : ViewModel() {
private val _devices = MutableStateFlow(emptyList<Device>())
val devices: StateFlow<List<Device>> = _devices
private val _ipAddress = MutableStateFlow("192.168.0.211")
val ipAddress: StateFlow<String> = _ipAddress
private val _port = MutableStateFlow(40000)
val port: StateFlow<Int> = _port
private val _timeout = MutableStateFlow(500)
val timeout: StateFlow<Int> = _timeout
private val _isSearching = MutableStateFlow(false)
val isSearching: StateFlow<Boolean> = _isSearching
fun updateIpAddress(newIpAddress: String) {
_ipAddress.value = newIpAddress
}
fun updatePort(newPort: Int) {
_port.value = newPort
}
fun updateTimeout(newTimeout: Int) {
_timeout.value = newTimeout
}
private var searchingProcess: Job? = null
private val udpClient = UdpClient()
fun findDevices() {
if (_isSearching.value) {
searchingProcess?.cancel()
_isSearching.value = false
return
}
searchingProcess = viewModelScope.launch {
_isSearching.value = true
var socket: DatagramSocket? = null
try {
withContext(Dispatchers.IO) {
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
for (slaveAddress in 1..247) {
if (!isActive) break
val data = ByteArray(4)
udpClient.sendPacket(
socket!!,
ipAddress.value,
port.value,
data
)
val response = udpClient.recievePacket(socket!!, timeout.value)
if (response != null) {
_devices.value = _devices.value + Device(slaveAddress, "КДЛ")
}
}
}
} finally {
socket?.close()
_isSearching.value = false
}
}
}
}
This is the UdpClient code ConnectDeviceViewModel uses:
<code>import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
class UdpClient {
fun sendPacket(socket: DatagramSocket, ipAddress: String, port: Int, data: ByteArray) {
val address = InetAddress.getByName(ipAddress)
val packet = DatagramPacket(data, data.size, address, port)
socket.send(packet)
}
fun recievePacket(socket: DatagramSocket, timeout: Int): ByteArray? {
val buffer = ByteArray(14)
val packet = DatagramPacket(buffer, buffer.size)
socket.soTimeout = timeout
return try {
socket.receive(packet)
val responseData = packet.data.sliceArray(0 until packet.length)
responseData
} catch (e: Exception) {
null
}
}
}
</code>
<code>import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
class UdpClient {
fun sendPacket(socket: DatagramSocket, ipAddress: String, port: Int, data: ByteArray) {
val address = InetAddress.getByName(ipAddress)
val packet = DatagramPacket(data, data.size, address, port)
socket.send(packet)
}
fun recievePacket(socket: DatagramSocket, timeout: Int): ByteArray? {
val buffer = ByteArray(14)
val packet = DatagramPacket(buffer, buffer.size)
socket.soTimeout = timeout
return try {
socket.receive(packet)
val responseData = packet.data.sliceArray(0 until packet.length)
responseData
} catch (e: Exception) {
null
}
}
}
</code>
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
class UdpClient {
fun sendPacket(socket: DatagramSocket, ipAddress: String, port: Int, data: ByteArray) {
val address = InetAddress.getByName(ipAddress)
val packet = DatagramPacket(data, data.size, address, port)
socket.send(packet)
}
fun recievePacket(socket: DatagramSocket, timeout: Int): ByteArray? {
val buffer = ByteArray(14)
val packet = DatagramPacket(buffer, buffer.size)
socket.soTimeout = timeout
return try {
socket.receive(packet)
val responseData = packet.data.sliceArray(0 until packet.length)
responseData
} catch (e: Exception) {
null
}
}
}
Additional info:
- socket.localPort method returns 40000
- NETSTAT shows no information about port 40000
- I use AVD for debugging
I tried different approaches on specifying port, but none of them worked.
<code>val socket = DatagramSocket(port.value)
</code>
<code>val socket = DatagramSocket(port.value)
</code>
val socket = DatagramSocket(port.value)
<code>var socket: DatagramSocket? = null
socket = DatagramSocket(InetSocketAddress("0.0.0.0", port.value))
</code>
<code>var socket: DatagramSocket? = null
socket = DatagramSocket(InetSocketAddress("0.0.0.0", port.value))
</code>
var socket: DatagramSocket? = null
socket = DatagramSocket(InetSocketAddress("0.0.0.0", port.value))
<code>var socket: DatagramSocket? = null
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
</code>
<code>var socket: DatagramSocket? = null
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
</code>
var socket: DatagramSocket? = null
socket = DatagramSocket(null)
socket!!.reuseAddress = true
socket!!.bind(InetSocketAddress(port.value))
New contributor
Dmitry Krylov is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.