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.
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
}
}
I'm trying to use a udp socket as server in Flutter. I'd like to bind this socket on my localhost at 6868 port always in listening. Unfortunately when i try to send something from a client,it never prints the string "RECEIVED".
Here's the code:
static Future openPortUdp(Share share) async {
await RawDatagramSocket.bind(InternetAddress.anyIPv4,6868)
.then(
(RawDatagramSocket udpSocket) {
udpSocket.listen((e) {
switch (e) {
case RawSocketEvent.read:
print("RECEIVED");
print(String.fromCharCodes(udpSocket.receive().data));
break;
case RawSocketEvent.readClosed:
print("READCLOSED");
break;
case RawSocketEvent.closed:
print("CLOSED");
break;
}
});
},
);
}
Am I doing something wrong?
Anyway this is the client side, it is written is Lua:
local udp1 = socket.udp()
while true do
udp1:setpeername("192.168.1.24", 6868)
udp1:send("HI")
local data1 = udp1:receive()
if (not data1 == nil) then print(data1) break end
udp1:close()
end
I tested it with another server and it works well, so i don't think the client is the problem.
Thanks!
If it can help you, here my code for my SocketUDP (as singleton) in my app.
I used it in localhost and it works very well :
class SocketUDP {
RawDatagramSocket _socket;
// the port used by this socket
int _port;
// emit event when receive a new request. Emit the request
StreamController<Request> _onRequestReceivedCtrl = StreamController<Request>.broadcast();
// to give access of the Stream to listen when new request is received
Stream<Request> get onRequestReceived => _onRequestReceivedCtrl.stream;
// as singleton to maintain the connexion during the app life and be accessible everywhere
static final SocketUDP _instance = SocketUDP._internal();
factory SocketUDP() {
return _instance;
}
SocketUDP._internal();
void startSocket(int port) {
_port = port;
RawDatagramSocket.bind(InternetAddress.anyIPv4, _port)
.then((RawDatagramSocket socket) {
_socket = socket;
// listen the request from server
_socket.listen((e) {
Datagram dg = _socket.receive();
if (dg != null) {
_onRequestReceivedCtrl.add(RequestConvert.decodeRequest(dg.data, dg.address));
}
});
});
}
void send(Request requestToSend, {bool isBroadCast:false}) {
_socket.broadcastEnabled = isBroadCast;
final String requestEncoded = RequestConvert.encodeRequest(requestToSend);
List<int> requestAsUTF8 = utf8.encode(requestEncoded);
_socket.send(requestAsUTF8, requestToSend.address, _port);
}
}
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 =>
}
}
}
}
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!