Using AyncTask to send a UDP packet - java

I am trying to send a UDP packet to a computer on the same network as my tablet. In order to do this, I began by setting up a class to hold all the appropriate objects that I need in order to create a UDP socket, create a packet, and then send that packet. This class is shown below:
public static class Session
{
public InetAddress address;
public DatagramSocket socket;
public DatagramPacket packet;
public String client;
public int port;
public byte[] receive_buffer;
public byte[] send_buffer;
public String message;
public Session (InetAddress address, DatagramSocket socket, DatagramPacket packet,
String client, int port, byte[] receive_buffer, byte[] send_buffer,
String message)
{
this.address = address;
this.socket = socket;
this.packet = packet;
this.client = client;
this.receive_buffer = receive_buffer;
this.send_buffer = send_buffer;
this.message = message;
this.port = port;
}
}
Whenever I try to send a UDP packet, I begin by creating a Session object that contains a socket, packet, message, and a few other things. I also have a Send class that I use to actually send the UDP packet. This is shown below:
public static Session Send (Session session)
{
// Execute within "try" function to catch exceptions
try
{
/* Create address*/
session.address = InetAddress.getByName(session.client);
/* Create socket */
session.socket = new DatagramSocket(session.port);
/* Create packet */
session.packet = new DatagramPacket(session.message.getBytes(),
session.message.length(), session.address, session.port);
/* Send packet */
session.socket.send(session.packet);
/* Return session */
return session;
}
catch (Exception e)
{
Log.e("MYAPP", "exception: " + e.getMessage());
Log.e("MYAPP", "exception: " + e.toString());
}
return null;
}
However, Send() cannot be called directly, since one cannot perform network operations on the UI thread. In order to remedy this, I created an AsyncTask that calls Send(). Now all I have to do is pass the Session object to the AsyncTask and it will send the packet (in theory). The AsyncTask that I created is shown below:
class sendData extends AsyncTask<UDP.Session, Void, UDP.Session>
{
/* Pre-Execute Function */
#Override
protected void onPreExecute ()
{
super.onPreExecute();
}
/* Main AsyncTask Function */
#Override
protected UDP.Session doInBackground(UDP.Session... arguments)
{
/* Send UDP packet */
UDP.Session session = UDP.Send(arguments[0]);
return session;
}
/* Post-Execute Function */
#Override
protected void onPostExecute (UDP.Session session)
{
super.onPostExecute(session);
}
}
The issue that I am experiencing is that I cannot figure out how to return the session object from my AsyncTask. It is critical that I return the session that I passed to the AsyncTask, because otherwise the socket/port becomes corrupted and I get binding exceptions and a whole bunch of other issues when I try to send another packet. I tried using:
UDP.Session nsession = new sendData().execute(ssession).get();
but I get an error that states "Unhandled exceptions: java.lang.InterruptedException, java.util.concurrent.ExecutionException". So my question is what is the best way for me to return the session object that I pass to the AsyncTask so that I can use that same session object next time I want to send a packet.

I was being silly and not paying attention to the compiler warnings about the unhandled exceptions. The AsyncTask call made above (UDP.Session nsession = new sendData().execute(ssession).get();) is indeed correct, but it just needs to be placed inside a try/catch statement catch any possible exceptions. When I changed my code to the following...
try{
session = new sendData().execute(session).get();}
catch (Exception exception){}
...everything worked. I am able to properly return an object from the AsyncTask, and my socket no longer gets corrupted when the AsyncTask finished, allowing me to send as many packets as I want

Related

Event driven and asynchronous serial port communication simultaneously

I'm completely new to serial port communication and need some help grasping it.
I need to communicate with a control board. This board can sometimes send events that I need to react to, and I need to send events to the board and await a response.
We have established a protocol where each event is always 12 bytes and the first 2 bytes determine the event type.
I know that when I send a specific message, I need to await a message with specific signifying bytes. At the same time I want it to be possible to react to events that are sent from the board. For instance the board might say that it is overheating, and at the same time I'm asking it to perform some command and reply.
My question is, if I write to the port and block for a second while awaiting the expected response, how I do ensure I don't "steal" the data my listener expects? E.g. do a serial ports work like a stream, where once I've read I've advanced past the point where it can be re-read.
I've done some implementation of this using jSerialComm, hopefully this can shed some light on my question.
First a listener that is registered using the addDataListener method. I want this to trigger when an event is present on the port that starts with "T".
private static LockerSerialPort getLockerSerialPort(final DeviceClient client) {
return MySerialPort.create(COM_PORT)
.addListener(EventListener.newBuilder()
.addEventHandler(createLocalEventHandler())
.build());
}
private static EventHandler createLocalEventHandler() {
return new EventHandler() {
#Override
public void execute(final byte[] event) {
System.out.println(new String(event));
}
#Override
public byte[] getEventIdentifier() {
// I want this listener to be executed when events that start with T are sent to the port
return "T".getBytes();
}
#Override
public String getName() {
return "T handler";
}
};
}
Next, I want to be able to write to the port and immediately get the response because it is needed to know if the command was successful or not.
private byte[] waitForResponse(final byte[] bytes) throws LockerException {
write(bytes);
return blockingRead();
}
private void write(final byte[] bytes) throws LockerException {
try (var out = serialPort.getOutputStream()) {
out.write(bytes);
} catch (final IOException e) {
throw Exception.from(e, "Failed to write to serial port %s", getComPort());
}
}
public byte[] blockingRead() {
return blockingRead(DEFAULT_READ_TIMEOUT);
}
private byte[] blockingRead(final int readTimeout) {
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, readTimeout, 0);
try {
byte[] readBuffer = new byte[PACKET_SIZE];
final int bytesRead = serialPort.readBytes(readBuffer, readBuffer.length);
if (bytesRead != PACKET_SIZE) {
throw RuntimeException.from(null, "Expected %d bytes in packet, got %d", PACKET_SIZE, bytesRead);
}
return readBuffer;
} catch (final Exception e) {
throw RuntimeException.from(e, "Failed to read packet within specified time (%d ms)", readTimeout);
}
}
When I call waitForResponse("command"), how do I know my blocking read doesn't steal data from my listener?
Are these two patterns incompatible? How would one usually handle a scenario like this?

Java socket multiple writes and reads

I want to write a client that can communicate to Vowpal Wabbit over TCP. Essentially, I need to send messages like a b | c d e to VW host over port 26542. VW responds with a message like 0.400000 0.200000 0.200000 0.200000 (not sure how the message terminates).
So, I need to do this multiple times - send message, receive message, send message, receive message, and so on.
I have the following code in Java.
public class MyClient {
protected String host;
protected int port;
protected Socket socket;
protected PrintWriter outputWriter;
protected BufferedReader inputReader;
public MyClient(String host, int port) throws IOException {
socket = new Socket(host, port);
outputWriter = new PrintWriter(socket.getOutputStream());
inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void send(final String message) throws IOException {
outputWriter.print(message+"\n"); // important to add a newline
outputWriter.flush();
String responseStr = inputReader.readLine();
System.out.println(responseStr);
if (StringUtils.isBlank(responseStr)) {
return;
}
}
}
I use this class as follows:
MyClient client = new MyClient("host_ip", 26542); // the port used by VW
client.send("1:0.5:0.3 | feature11 feature21 feature31");
client.send("1:0.5:0.3 | feature12 feature22 feature32");
client.send("1:0.5:0.3 | feature13 feature23 feature33");
With the above code, only the response of the first "send" is printed. The other two return null responses.
I also tried with "send" only code:
public void send(final String message) throws IOException {
outputWriter.print(message+"\n"); // important to add a newline
outputWriter.flush();
}
It turns out that only the first message is sent (I have a way of verifying/logging on server side what it receives from my client).
Why is it that only the first send succeeds but all other sends fail (although no exception is raised)? How do I fix this?
If readLine() returns null, the peer has closed the connection.

The write() method of a SocketChannel do not throw an exception when it should do

I'm writing a server to exchange messages among clients. One issue left to be solved is how to release a channel when a client happens to be closed. What I do is to start a monitor thread in which the all-Clients map is monitored, and I attempt to remove() a channel if an exception been detected when trying write() to it. However, after closing a client, the write() method in monitor thread don't throw an exception so the useless channel will never be released. Anybody know why?
public class ServerMonitor extends Thread{
private Map<String, SocketChannel> allClients;
private Set set;
private Iterator it;
private Entry entry;
private SocketChannel channel;
private ByteBuffer buf;
public ServerMonitor(Map<String, SocketChannel> allClients) {
this.allClients = allClients;
buf = ByteBuffer.allocateDirect(10);
byte b = 0;
buf.put(b);
buf.flip();
}
public void run(){
while(true) {
if(!allClients.isEmpty()) {
set = allClients.entrySet();
it = set.iterator();
while(it.hasNext()) {
entry = (Entry) it.next();
channel = (SocketChannel) entry.getValue();
try{
channel.write(buf);
} catch(Exception e) {
allClients.remove(entry.getKey());
//set.remove(entry);
}
}
}
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Writing to a TCP socket is buffered locally and put on the wire asynchronously. So you can't rely on the first write after the peer closes to fail. You can rely on a subsequent write failing, but it could take a number of writes to get there.
I've run into this issue when writing applications that send data over TCP. You've discovered that the only real way to know if a client has closed the connection is by the IOException on a call to write(...). This is pretty much the way it works.
There is a cleaner solution. First of all, you must always handle the case that a client disconnects without you knowing, and properly remove them when you get the IOException on write(...). However, if the client sends a message telling the server it is disconnecting, you can use that to close the connection when you see it.

Writing to an AsynchronousSocketChannel and processing the data in an Event-based way

I'm trying to figure out how to send data between sockets in Java (this is part of a bigger project and I'll get back and answer my previous two questions related to that once I can resolve this..). I would like to connect a client and a server socket asynchronously in Java, and then send messages between them, and get a callback, say, when I have sent a message from the client to the server.
I think I have managed to get the set-up working. Here is my code:
private AsynchronousServerSocketChannel socListener;
private AsycnchrnonousSocketChannel socClient;
//This is the GUI callback for the button that initiates the socket server
private void button_StartSocketServerActionPerformed(ava.awt.event.ActionEvent evt)
{
try{
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
m_socListener= AsynchronousServerSocketChannel.open().bind(ipSocket);
m_socListener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>()
{
#Override
public void completed(AsynchronousSocketChannel ch, Void att)
{
// accept the next connection
m_socListener.accept(null, this);
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) { }
}
);
}
catch (Exception e){
}
}
//This is the GUI callback for the button that initiates the client socket
private void button_StartClientSocketActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
socClient=AsynchronousSocketChannel.open();
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
socClient.connect(ipSocket, null, new CompletionHandler<Void,Void>()
{
#Override
public void completed(Void att1, Void att2)
{
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) {}
}
);
}
catch (Exception e){
}
}
I'm including the server and the client in the same file for simplicity of testing.
So supposing the connection is successfully established, and I have a process on a timer (say) that was writing data to the server socket, I'd like to have the client socket 'listen' for this new data being sent from the server and then generate a callback when a write occurs (without doing something like periodically checking via a timer and a while loop to check that whether new data has been added). This is accomplishable in C# and a nice tutorial is available at:
http://www.developerfusion.com/article/3918/socket-programming-in-c-part-1/2/
Any tips on how to do this would be greatly appreciated. Thanks!
Chris
You could use RMI to accomplish that, the documentation can be found there:
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136424.html
With this, your server could notify your client as much as you need.

JAVA server and .Net client programming

I am doing communication with Java server.
One application which is developed in java and it runs on some ip,port.
e.g. 192.168.1.1 port 9090
No wi want to communicate to that server using my ASp .NET ( C# )
I have following scenario:
connection with server
once the data has been trasferred, i have to inform the server that my data transfer is complete. So after that the server will process the data and will revert me(respone).
Then i will have to read that data.
When i am using the NetworkStream class.
I have 1 method which i am using is write to send data.
But the server dont understand the complete data has been received or not.
So it continuously wait for the data.
So how to do this?
Maybe you could consider to use Eneter Messaging Framework for that communication.
It is the lightweight cross-platform framework for the interprocess communication.
The Java service code would look something like this:
// Declare your type of request message.
public static class MyRequestMsg
{
public double Number1;
public double Number2;
}
// Declare your type of response message.
public static class MyResponseMsg
{
public double Result;
}
public static void main(String[] args) throws Exception
{
// Create receiver that receives MyRequestMsg and
// responses MyResponseMsg
IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
myReceiver =
aReceiverFactory.createDuplexTypedMessageReceiver(MyResponseMsg.class, MyRequestMsg.class);
// Subscribe to handle incoming messages.
myReceiver.messageReceived().subscribe(myOnMessageReceived);
// Create input channel listening to TCP.
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel anInputChannel =
aMessaging.createDuplexInputChannel("tcp://127.0.0.1:4502/");
// Attach the input channel to the receiver and start the listening.
myReceiver.attachDuplexInputChannel(anInputChannel);
System.out.println("Java service is running. Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
// Detach the duplex input channel and stop the listening.
// Note: it releases the thread listening to messages.
myReceiver.detachDuplexInputChannel();
}
private static void onMessageReceived(Object sender,
TypedRequestReceivedEventArgs<MyRequestMsg> e)
{
// Get the request message.
MyRequest aRequest = e.getRequestMessage();
... process the request ...
// Response back the result.
MyResponseMsg aResponseMsg = new MyResponseMsg();
... set the result in the response message ...
try
{
// Send the response message.
myReceiver.sendResponseMessage(e.getResponseReceiverId(), aResponseMsg);
}
catch (Exception err)
{
EneterTrace.error("Sending the response message failed.", err);
}
}
// Handler used to subscribe for incoming messages.
private static EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>> myOnMessageReceived
= new EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>>()
{
#Override
public void onEvent(Object sender, TypedRequestReceivedEventArgs<MyRequestMsg> e)
{
onMessageReceived(sender, e);
}
};
And the .NET client would look something like this:
public class MyRequestMsg
{
public double Number1 { get; set; }
public double Number2 { get; set; }
}
public class MyResponseMsg
{
public double Result { get; set; }
}
private IDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg> myMessageSender;
private void OpenConnection()
{
// Create message sender.
// It sends string and as a response receives also string.
IDuplexTypedMessagesFactory aTypedMessagesFactory = new DuplexTypedMessagesFactory();
myMessageSender =
aTypedMessagesFactory.CreateDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg>();
// Subscribe to receive response messages.
myMessageSender.ResponseReceived += OnResponseReceived;
// Create TCP messaging.
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexOutputChannel anOutputChannel =
aMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:4502/");
// Attach the output channel to the message sender and be able
// send messages and receive responses.
myMessageSender.AttachDuplexOutputChannel(anOutputChannel);
}
private void CloseConnection(object sender, FormClosedEventArgs e)
{
// Detach output channel and stop listening to response messages.
myMessageSender.DetachDuplexOutputChannel();
}
private void SendMessage()
{
// Create message.
MyRequestMsg aRequestMessage = new MyRequestMsg();
...
// Send message.
myMessageSender.SendRequestMessage(aRequestMessage);
}
private void OnResponseReceived(object sender,
TypedResponseReceivedEventArgs<MyResponseMsg> e)
{
// Get the response message.
MyResponseMsg aResponse = e.ResponseMessage;
.... process the response from your Java client ....
}

Categories