UDP listener and broadcast message to main Activity - android-activity

I have an android app with MainActivity.
I have succesfully deployed a BroadCastReceiver and I can receive messages.
Now I have another class that listens for new UDP messages on specific port. I would like to pass the received messages to my MainActivity so I could update some values here.
For some reason I cannot make BroadCasting from this class.
Here is the code:
MainActivity.kt
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//hide top bar
supportActionBar?.hide()
//register broadcastreceiver
registerReceiver(mPlugInReceiver, getIntentFilter())
Log.d(TAG, "Registered broadcastreceiver")
//sending test message to broadcastreceiver, this works
val intent = Intent()
intent.action = "MESSAGE_RECEIVED"
intent.putExtra("MESSAGE_STRING", "sending test message to broadcastreceiver")
sendBroadcast(intent)
//start UDP server
val udpServer = udpServer()
Thread(udpServer).start()
}
udpServer.kt
class udpServer : Runnable {
private val UDP_PORT = 58651
override fun run() {
var run = true
Log.d(MainActivity.TAG, "udpServer started")
while (run) {
try {
val udpSocket = DatagramSocket(UDP_PORT)
val message = ByteArray(8000)
val packet = DatagramPacket(message, message.size)
//Log.i(MainActivity.TAG, "UDP server about to wait to receive")
udpSocket.receive(packet)
val text = String(message, 0, packet.length)
//Log.d(MainActivity.TAG, text)
//This does not work
val intent = Intent()
intent.action = "MESSAGE_RECEIVED"
intent.putExtra("MESSAGE_STRING", "sending test message to broadcastreceiver")
//This throws error: "create function 'sendBroadcast'"
sendBroadcast(intent)
} catch (e: IOException) {
//Log.e(MainActivity.TAG, "error: ", e)
//run = false
}
}
}
}
I tried to use companion object to pass data, but it doesn't work either.

Related

Jetpack Composables with TCP Socket Connection Crashing

I am using Jetpack Composables and Android WiFi P2P API guide to create buttons and animation but trying to maintain an active TCP socket to output and receive data. However, whenever the program tries to establishes the connection using "socket.connect((InetSocketAddress())" it crashes the app.
class MainActivity : ComponentActivity() {
val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {
getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
}
var channel: WifiP2pManager.Channel? = null
var receiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Obtain an instance of WifiP2pManager and register application with the Wi-Fi P2P framework
// Initialize() method returns a WifiP2pManager.Channel, which is used to connect application to the Wi-Fi P2P framework
channel = manager?.initialize(this, mainLooper, null)
channel?.also { channel ->
receiver = manager?.let { WiFiDirectBroadcastReceiver(it, channel) }
}
setContent {
createButtons()
createAnimatingImages()
val socket = Socket()
var buf = ByteArray(1024)
try {
socket.bind(null)
socket.connect((InetSocketAddress(host, port)), 500)
if (socket.isConnected) {
println("Client Connected to " + host + " at " + port)
}
try {
val outputStream: OutputStream = socket.getOutputStream()
buf = doSomething(...)
outputStream.write(buf)
outputStream.flush()
} catch (e: IOException) {
println("IO Exception")
e.printStackTrace()
}
} catch (e: IOException) {
//catch logic
}
}

Service Binder object casting issue during service connection

I have an issue in service connection issue in that line var binder:TwentyFourHoursService.LocalBinder = service as TwentyFourHoursService.LocalBinder and could not find solution:
override fun onServiceConnected(
className: ComponentName,
service: IBinder
) { // cast the IBinder and get MyService instance
var binder:TwentyFourHoursService.LocalBinder = service as TwentyFourHoursService.LocalBinder
myService = binder.getService()
bound = true
// serviceCallbacks =this as ServiceCallbacks
myService!!.setCallbacks(mActivity) // register
}
Here is my service:
class TwentyFourHoursService : Service() {
private val mHandler: Handler = Handler() //run on another Thread to avoid crash
private var mTimer: Timer? = null //timer handling
// Binder given to clients
private val binder: IBinder = LocalBinder()
override fun onBind(intent: Intent): IBinder {
// throw UnsupportedOperationException("Not yet implemented")
return binder
}
override fun onCreate() {
if (mTimer != null) // Cancel if already existed
mTimer!!.cancel() else mTimer = Timer() //recreate new
mTimer!!.scheduleAtFixedRate(
TimeDisplay(),
0,
notify
) //Schedule task
//Timer().scheduleAtFixedRate(TimeDisplay(),0, notify)
}
fun setCallbacks(callbacks: ServiceCallbacks?) {
serviceCallbacks = callbacks
}
override fun onDestroy() {
super.onDestroy()
mTimer!!.cancel() //For Cancel Timer
Toast.makeText(this, "Service is Destroyed", Toast.LENGTH_SHORT).show()
}
//class TimeDisplay for handling task
internal inner class TimeDisplay : TimerTask() {
override fun run() { // run on another thread
mHandler.post(Runnable {
// display toast
/* if (serviceCallbacks!=null) {
serviceCallbacks!!.doSomething()
}*/
// Reload current fragment
// Reload current fragment
// startActivity(Intent(applicationContext, FitnessSlideMenuScreen::class.java))
// rFitnessSlideMenuScreen().displaySelectedFragment(HomeFragment())
Toast.makeText(applicationContext, "Service is running", Toast.LENGTH_SHORT).show()
})
}
}
Error:
***java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.example.beyahfitness.service.TwentyFourHoursService$LocalBinder***
The issue as I realised was as a result of the way had declared my service in Manifest,
<service
android:name=".MyService"
android:enabled="true"
android:process=":MyService" >
When I try getting the service at;
override fun onServiceConnected(name: ComponentName,service: IBinder)
I kept getting this error; java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.demo.MyService$LocalBinder
I resolved to refactoring my Service as below;
<service
android:name=".MyService" >
This apparently solves my problem, hope it helps you too

ObjectInputStream readObject unexpectedly closing socket

I want to set up a Server/Client where the client sends a serializable object over a socket to the server. For some reason, I keep getting java.net.SocketException: SocketClosed when I try to read the object sent to the server.
Here is my code for the client:
class Client(address: String, port: Int) {
private val connection: Socket = Socket(address, port)
private var connected: Boolean = true
private val writer = ObjectOutputStream(connection.getOutputStream())
private val reader = ObjectInputStream(connection.getInputStream())
init {
println("Connected to server at $address on port $port")
}
fun run() {
var sent = false
while (connected) {
try {
if (!sent) {
sent = true
writer.use {
it.writeObject("Hello")
it.flush()
}
println("Sent")
} else {
println("Didn't send")
}
Thread.sleep(1000)
} catch (ex: Exception) {
ex.printStackTrace()
shutdown()
}
}
}
...
}
and here is the code for the server:
class ClientHandler(private val client: Socket) {
private val reader = ObjectInputStream(client.getInputStream())
private val writer = ObjectOutputStream(client.getOutputStream())
private var running: Boolean = false
fun run() {
running = true
while (running) {
try {
reader.use {
val packet = it.readObject()
when (packet) {
is String -> {
println("Received packet with data: ${packet}")
}
}
}
} catch (ex: Exception) {
ex.printStackTrace()
shutdown()
}
}
}
...
}
The output on my server is
Server is running on port 9999
Client connected: 127.0.0.1
Received packet with data: Hello
java.net.SocketException: Socket closed
at java.base/java.net.SocketInputStream.socketRead0(Native Method)
at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
...
So, it seems like one instance of my String is making it across, but later calls claim that the socket is closed.
Every other post I've seen related to this problem claims that the sender (client) is closing the socket early. However, I know that the client is not closing the socket through its own means. If I change my client code to:
class Client(address: String, port: Int) {
...
private val writer = connection.getOutputStream() // Regular streams
private val reader = Scanner(connection.getInputStream())
...
fun run() {
var sent = false
while (connected) {
try {
if (!sent) {
sent = true
writer.write("Hello\n".toByteArray()) // Send regular byte array
println("Sent")
} else {
println("Didn't send")
}
...
}
and my server code to:
class ClientHandler(private val client: Socket) {
private val reader = Scanner(client.getInputStream()) // Regular streams
private val writer = client.getOutputStream()
private var running: Boolean = false
fun run() {
running = true
while (running) {
try {
// Just read lines from stream
println(reader.nextLine())
}
...
}
then my output is what I expect:
Server is running on port 9999
Client connected: 127.0.0.1
Hello
My only hypothesis is that .readObject() is somehow closing the socket connection, forcing the next readObject() to throw an exception. This doesn't make too much sense to me, though. Why would that happen?
Digging around through the code for a bit more gave me the answer I needed. It looks like .use closes the socket after it finishes. Removing the use { } blocks made this work as expected.

How do I multithread my Scala server?

I've been programming a simple client/server application that sends one response back in Scala, and I've been trying to multithread my server using ExecutionContext without any luck.
This is my server code, I think the position of my execute block is causing errors:
import java.net._;
import java.io._;
import scala.concurrent.ExecutionContext
object ServerTwo extends App {
var s1: Socket = null;
var dis: DataInputStream = null;
var s1In: InputStream= null;
var o1out: OutputStream = null;
var odos: DataOutputStream = null
while(true){
def execute(body: =>Unit)=
ExecutionContext.global.execute( new Runnable {def run()= body})
try{
// Open your connection to a server, at port 1234
var s: ServerSocket = new ServerSocket(999)
s1 = s.accept(); // Wait and accept a connection
execute{
s1In = s1.getInputStream()
dis = new DataInputStream(s1In)
var st = new String (dis.readUTF())
//println("Word received is "+st )
st="Received message";
var o1out: OutputStream = null; var odos: DataOutputStream = null
o1out = s1.getOutputStream()
odos = new DataOutputStream (o1out)
// Send the string back
odos.writeUTF(st);
}//end execute
}//end try
catch {
case e: Exception =>
} finally {
// Close the connection, but not the server socket
try{
s1.close()
}
catch{
case e: Exception =>
}
}
}
}

netty issue when writeAndFlush called from different InboundChannelHandlerAdapter.channelRead

I've got an issue, for which I am unable to post full code (sorry), due to security reasons. The gist of my issue is that I have a ServerBootstrap, created as follows:
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
final ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, 3000));
//Adds the MQTT encoder and decoder
ch.pipeline().addLast("decoder", new MyMessageDecoder());
ch.pipeline().addLast("encoder", new MyMessageEncoder());
ch.pipeline().addLast(createMyHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
channelFuture = b.bind(listenAddress, listenPort);
With createMyHandlerMethod() that basically returns an extended implementation of ChannelInboundHandlerAdapter
I also have a "client" listener, that listens for incoming connection requests, and is loaded as follows:
final String host = getHost();
final int port = getPort();
nioEventLoopGroup = new NioEventLoopGroup();
bootStrap = new Bootstrap();
bootStrap.group(nioEventLoopGroup);
bootStrap.channel(NioSocketChannel.class);
bootStrap.option(ChannelOption.SO_KEEPALIVE, true);
bootStrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, getKeepAliveInterval()));
ch.pipeline().addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimeoutHandler());
ch.pipeline().addLast("decoder", new MyMessageDecoder());
ch.pipeline().addLast("encoder", new MyMessageEncoder());
ch.pipeline().addLast(MyClientHandler.this);
}
})
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.TCP_NODELAY, true);
// Start the client.
try {
channelFuture = bootStrap.connect(host, port).sync();
} catch (InterruptedException e) {
throw new MyException(“Exception”, e);
}
Where MyClientHandler is again a subclassed instance of ChannelInboundHandlerAdapter. Everything works fine, I get messages coming in from the "server" adapter, i process them, and send them back on the same context. And vice-versa for the "client" handler.
The problem happens when I have to (for some messages) proxy them from the server or client handler to other connection. Again, I am very sorry for not being able to post much code, but the gist of it is that I'm calling from:
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(someOtherMessage);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
Now here's the problem: the bolded (client) writeAndFlush - never actually writes the message bytes, it doesn't throw any errors. The ChannelFuture returns all false (success, cancelled, done). And if I sync on it, eventually it times out for other reasons (connection timeout set within my code).
I know I haven't posted all of my code, but I'm hoping that someone has some tips and/or pointers for how to isolate the problem of WHY it is not writing to the client context. I'm not a Netty expert by any stretch, and most of this code was written by someone else. They are both subclassing ChannelInboundHandlerAdapter
Feel free to ask any questions if you have any.
*****EDIT*********
I tried to proxy the request back to a DIFFERENT context/channel (ie, the client channel) using the following test code:
public void proxyPubRec(int messageId) throws MQTTException {
logger.log(logLevel, "proxying PUBREC to context: " + debugContext());
PubRecMessage pubRecMessage = new PubRecMessage();
pubRecMessage.setMessageID(messageId);
pubRecMessage.setRemainingLength(2);
logger.log(logLevel, "pipeline writable flag: " + ctx.pipeline().channel().isWritable());
MyMQTTEncoder encoder = new MyMQTTEncoder();
ByteBuf buff = null;
try {
buff = encoder.encode(pubRecMessage);
ctx.channel().writeAndFlush(buff);
} catch (Throwable t) {
logger.log(Level.SEVERE, "unable to encode PUBREC");
} finally {
if (buff != null) {
buff.release();
}
}
}
public class MyMQTTEncoder extends MQTTEncoder {
public ByteBuf encode(AbstractMessage msg) {
PooledByteBufAllocator allocator = new PooledByteBufAllocator();
ByteBuf buf = allocator.buffer();
try {
super.encode(ctx, msg, buf);
} catch (Throwable t) {
logger.log(Level.SEVERE, "unable to encode PUBREC, " + t.getMessage());
}
return buf;
}
}
But the above at line: ctx.channel().writeAndFlush(buff) is NOT writing to the other channel - any tips/tricks on debugging this sort of issue?
someOtherMessage has to be ByteBuf.
So, take this :
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(someOtherMessage);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
... and replace it with this :
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(ByteBuf);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
Actually, this turned out to be a threading issue. One of my threads was blocked/waiting while other threads were writing to the context and because of this, the writes were buffered and not sent, even with a flush. Problem solved!
Essentially, I put the first message code in an Runnable/Executor thread, which allowed it to run separately so that the second write/response was able to write to the context. There are still potentially some issues with this (in terms of message ordering), but this is not on topic for the original question. Thanks for all your help!