int socket response is not shown by nc - kotlin

I'm running a simple tcp server at port 8080 with Netty that responds with hello when a connection is made.
class MyHandler : ChannelInboundHandlerAdapter() {
override fun channelActive(ctx: ChannelHandlerContext) {
val time = ctx.alloc().buffer(4)
time.writeBytes("hello".toByteArray())
val future = ctx.writeAndFlush(time)
future.addListener(ChannelFutureListener.CLOSE)
}
}
If I run nc localhost 8080, I get hello response. Everything ok. But when I change my code to respond with 1234 (integer) instead, I get an empty response from nc.
class MyHandler : ChannelInboundHandlerAdapter() {
override fun channelActive(ctx: ChannelHandlerContext) {
val time = ctx.alloc().buffer(4)
time.writeInt(1234) // <-- this is the change
val future = ctx.writeAndFlush(time)
future.addListener(ChannelFutureListener.CLOSE)
}
}

The nc program has no idea that you are sending an integer. So when it receives it, it has no idea what would be an appropriate way to display it.
If you were expecting to literally see "1234", then you were expecting magic. How could nc know that the data it received was an encoded integer? If you're going to implement a protocol to send data over TCP, you have to implement it on both ends or you will get garbage on the end that doesn't understand the protocol.

Related

TCP/IP Client in Kotlin that does not wait forever for server message

I have simple TCP/IP client code in Kotlin below.
This code works.
The client opens the socket and loops forever, first sending a message to the server, and then waiting forever for a response form the server.
I know this code isn’t great, looping forever, keeping the socket connection open etc., but it is just for test purposes right now.
fun tcp_client() {
thread {
val client1 = Socket(SERVER_IP_ADDRESS, SERVER_IP_PORT)
val output1 = PrintWriter(client1.getOutputStream(), true)
val input1 = BufferedReader(InputStreamReader(client1.inputStream))
while (true) {
output1.println(str_user_text)
str_rcvd_data = input1.readLine()
}
}
client1.close()
}
The line:
str_rcvd_data = input1.readLine()
waits forever for a server response.
My question: Is it possible to modify this code so that the client does NOT wait forvever for a server response? Something like this:
If (server data received) {
// process the data
} else {
// do something else for now and check again in a short while
}
Thanks in advance for any suggestions
Garrett
I eventually worked this out - I am not sure how 'correct' this solution is, but it works for me:
Connecting to the server....
My old code would hang if it couldn't connect, because the call to Socket() with the IP address and Port is a Blocking call - i.e.e wait forever:
val client1 = Socket(SERVER_IP_ADDRESS, SERVER_IP_PORT)
So I replaced the code with this:
try {
client1 = Socket()
client1.connect(InetSocketAddress(SERVER_IP_ADDRESS, SERVER_IP_PORT), 3000)
output1 = DataOutputStream (client1.getOutputStream())
input1 = DataInputStream (client1.getInputStream())
} catch (ex : Exception) {
// do something
} finally {
// do something
}
This isn't perfect, but it works.
For reading the data, my old code called readline() which is blocking:
str_rcvd_data = input1.readLine()
Now, my code first checks if there is any data and then grabs each byte
iRxDataAvailable = input1.available()
while (iRxDataAvailable > 0)
{
iRxDataAvailable--
// Take a copy of the received byte
byRcvdByte = input1.readByte()
// Do something with this data byte...
}
Finally, to send data to the server, the data is placed in a byte array, and then:
output1.write(byArray)

how to add feedback between client and server in Kotlin?

I am writing a simple client - server in Kotlin. There was a problem sending data from the server to the client.
Server: without the "writer" everything works fine and the message comes from the client
Client: without "reader" everything works fine and the server accepts the message.
As soon as I try to add "feedback" to the server and client, everything immediately stops working.
I understand that streams need to be closed, but I cannot understand at what point exactly. I tried many options - it does not work
Server:
import java.net.ServerSocket
import java.util.*
fun main() {
val server = ServerSocket(9000)
val client = server.accept()
val reader = Scanner(client.getInputStream())
val writer = client.getOutputStream()
print(reader.nextLine())
writer.write("Yes".toByteArray())
writer.flush()
}
Client
import java.net.Socket
import java.util.*
fun main() {
val client = Socket("192.168.1.8", 9000)
var writer = client.getOutputStream()
var reader = Scanner(client.getInputStream())
writer.write("Hi".toByteArray())
writer.flush()
print(reader.nextLine())
}
It looks like you're missing newlines in both messages, so the calls to reader.nextLine() never return, because the 'next line' hasn't been completely received. When using nextLine() you need to think of the communication protocol as "newline delimited messages".
Note that this also means you can't have newlines in your messages. If you need more complex messages you may want to consider base 64 encoding the message content.
Working with low level socket protocols can be very challenging, using a higher level protocol like HTTP adds complexity but can also be simpler in some ways.
If you need to use sockets you're likely better off reading a byte at a time and implementing a state machine to process bytes to output, though this will be much more complex than calling nextLine().
The following code works for me:
Server:
import java.net.ServerSocket
import java.util.*
fun main() {
val server = ServerSocket(9000)
val client = server.accept()
val reader = Scanner(client.getInputStream())
val writer = client.getOutputStream()
print(reader.nextLine())
writer.write("Yes\n".toByteArray()) // <<<<<< Added \n
writer.flush()
}
Client:
import java.net.Socket
import java.util.*
fun main() {
val client = Socket("127.0.0.1", 9000) // << Also changed to localhost IP.
var writer = client.getOutputStream()
var reader = Scanner(client.getInputStream())
writer.write("Hi\n".toByteArray()) // <<<<< Added \n
writer.flush()
print(reader.nextLine())
}

ktor websocket listener for new message

Is there a way to run some code each time a ktor websocket receives a new message, kind of like onTouchEvent in Android views?
Currently I check for new messages and process them in a while loop as follows:
while (websocketIsOpen) {
val newMessage = session!!.incoming.receive()
processMessage(newMessage)
}
where session is a DefaultClientWebsocketSession?, and processMessage is a method that has a Frame as a parameter.
I would prefer to set code that runs each time a new message is received, something like the following:
session!!.incoming.onNewMessage = { newMessage ->
processMessage(newMessage)
}
You can use consumeEach method of the incoming frames channel to run some code when a frame is received:
webSocket("/") {
incoming.consumeEach { frame ->
if (frame is Frame.Text) {
println("They say ${frame.readText()}")
}
}
}

How can I get a non-blocking infinite loop in a Kotlin Actor?

I would like to consume some stream-data using Kotlin actors
I was thinking to put my consumer inside an actor, while it polls in an infinite loop while(true). Then, when I decide, I send a message to stop the consumer.
Currently I have this:
while(true) {
for (message in channel){ <--- blocked in here, waiting
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
The problem
The problem with this is that it only runs when I send a message to the actor, so my consumer is not polling the rest of the time because channel is blocking waiting to receive the next message
Is there any alternative?, someone with the same issue?, or something similar to actors but not blocked by channel in Kotlin?
Since the channel is just a Channel (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html) you can first check if the channel is empty and if so start your polling. Otherwise handle the messages.
E.g.
while(true) {
while (channel.isNotEmpty()) {
val message = channel.receive()
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
In the end I used AKKA with Kotlin, I'm finding much easier this way
You should use postDelayed(), for example:
final Runnable r = new Runnable() {
public void run() {
// your code here
handler.postDelayed(this, 1000)
}
}
You can change 1000 with the the millisecond delay you want. Also I highly recommend to put your code inside a thread (if you are not already have) to prevent ANR (App Not Responding)

How can a RabbitMQ Client tell when it loses connection to the server?

If I'm connected to RabbitMQ and listening for events using an EventingBasicConsumer, how can I tell if I've been disconnected from the server?
I know there is a Shutdown event, but it doesn't fire if I unplug my network cable to simulate a failure.
I've also tried the ModelShutdown event, and CallbackException on the model but none seem to work.
EDIT-----
The one I marked as the answer is correct, but it was only part of the solution for me. There is also HeartBeat functionality built into RabbitMQ. The server specifies it in the configuration file. It defaults to 10 minutes but of course you can change that.
The client can also request a different interval for the heartbeat by setting the RequestedHeartbeat value on the ConnectionFactory instance.
I'm guessing that you're using the C# library? (but even so I think the others have a similar event).
You can do the following:
public class MyRabbitConsumer
{
private IConnection connection;
public void Connect()
{
connection = CreateAndOpenConnection();
connection.ConnectionShutdown += connection_ConnectionShutdown;
}
public IConnection CreateAndOpenConnection() { ... }
private void connection_ConnectionShutdown(IConnection connection, ShutdownEventArgs reason)
{
}
}
This is an example of it, but the marked answer is what lead me to this.
var factory = new ConnectionFactory
{
HostName = "MY_HOST_NAME",
UserName = "USERNAME",
Password = "PASSWORD",
RequestedHeartbeat = 30
};
using (var connection = factory.CreateConnection())
{
connection.ConnectionShutdown += (o, e) =>
{
//handle disconnect
};
using (var model = connection.CreateModel())
{
model.ExchangeDeclare(EXCHANGE_NAME, "topic");
var queueName = model.QueueDeclare();
model.QueueBind(queueName, EXCHANGE_NAME, "#");
var consumer = new QueueingBasicConsumer(model);
model.BasicConsume(queueName, true, consumer);
while (!stop)
{
BasicDeliverEventArgs args;
consumer.Queue.Dequeue(5000, out args);
if (stop) return;
if (args == null) continue;
if (args.Body.Length == 0) continue;
Task.Factory.StartNew(() =>
{
//Do work here on different thread then this one
}, TaskCreationOptions.PreferFairness);
}
}
}
A few things to note about this.
I'm using # for the topic. This grabs everything. Usually you want to limit by a topic.
I'm setting a variable called "stop" to determine when the process should end. You'll notice the loop runs forever until that variable is true.
The Dequeue waits 5 seconds then leaves without getting data if there is no new message. This is to ensure we listen for that stop variable and actually quit at some point. Change the value to your liking.
When a message comes in I spawn the handling code on a new thread. The current thread is being reserved for just listening to the rabbitmq messages and if a handler takes too long to process I don't want it slowing down the other messages. You may or may not need this depending on your implementation. Be careful however writing the code to handle the messages. If it takes a minute to run and your getting messages at sub-second times you will run out of memory or at least into severe performance issues.