How to make a asnychron REST Server with communication to external hardware - java

I am currently working on a REST server in Spring Boot that also communicates with external hardware via USB or TCP/IP. A command is sent to the external device, then I wait 2 seconds for the response and return it to the RestController.
For the USB communication I am currently using jSerialComm. For the TCP/IP communication I use sockets.
The whole thing also works so far when I use Thread.sleep. However, I would prefer it to be more dynamic, i.e. without the sleep, because TCP/IP can cause delays.
For me Java and REST are still new. Is there a way to let the server communicate asynchronously with the hardware?
#RestController
#RequestMapping("/api/v1")
public class CommController {
#GetMapping("/Version")
public String getVersion() {
Serial serial = new Serial();
String s_response = null;
s_response = serial.getVersion();
return s_response;
}
#GetMapping("/VersionTCPIP")
public String getVersionTCPIP() {
Serial serial = new Serial();
String s_response = null;
s_response = serial.getVersionTCPIP();
return s_response;
}
}
USB/serial-class:
public class Serial {
private static SerialPort port;
private static List<Byte> l_readBuffer;
private static final class MessageListener implements SerialPortDataListener
{
#Override
public int getListeningEvents()
{
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
#Override
public void serialEvent(SerialPortEvent event)
{
if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE)
return;
byte[] newData = new byte[port.bytesAvailable()];
int numRead = port.readBytes(newData, newData.length);
for (int i = 0; i < numRead; i++)
{
l_readBuffer.add(newData[i]);
}
System.out.println("Read " + numRead + " bytes.");
}
}
public String getVersion() {
SerialPort[] ports = SerialPort.getCommPorts();
port = null;
for (SerialPort currentPort :
ports)
{
if (currentPort.getDescriptivePortName().contains("XXX"))
{
port = currentPort;
break;
}
}
Objects.requireNonNull(port).setBaudRate(9600);
port.setParity(SerialPort.NO_PARITY);
port.setNumStopBits(SerialPort.ONE_STOP_BIT);
port.setNumDataBits(8);
port.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
//port.clearRTS();
port.setComPortTimeouts(SerialPort.LISTENING_EVENT_DATA_AVAILABLE, 5000, 5000);
port.openPort();
MessageListener listener = new MessageListener();
port.addDataListener(listener);
l_readBuffer = new ArrayList<>();
byte[] sendBuffer = new byte[5];
// fill sendBuffer
port.writeBytes(sendBuffer, sendBuffer.length);
try
{
Thread.sleep(2000);
} catch (Exception e)
{
e.printStackTrace();
}
System.out.println("Data raw: " + l_readBuffer.toString());
byte[] ba_responseBuffer = new byte[l_readBuffer.size()];
for (int i = 0; i < l_readBuffer.size(); i++)
{
ba_responseBuffer[i] = l_readBuffer.get(i);
}
String s_version = new String(ba_responseBuffer);
System.out.println("Version: " + s_version);
port.removeDataListener();
port.closePort();
return s_version;
}
public String getVersionTCPIP()
{
Socket socket;
String s_versionString = null;
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(s_hostnameTCPIP, i_port), 1000);
byte[] ba_sendBuffer = new byte[1024];
Arrays.fill(ba_sendBuffer, (byte) 0x00);
// fill sendBuffer
// send data
DataOutputStream dOut = new DataOutputStream(socket.getOutputStream());
dOut.write(ba_sendBuffer); // write the message
dOut.writeInt(i_sendLength); // write length of the message
dOut.flush();
try
{
Thread.sleep(2000);
} catch (Exception e)
{
e.printStackTrace();
}
byte[] ba_responseBuffer = new byte[0];
if (socket.isConnected())
{
try
{
InputStream inFromServer = socket.getInputStream();
DataInputStream dIn = new DataInputStream(inFromServer);
synchronized (dIn)
{
int length = dIn.available();
ba_responseBuffer = new byte[length];
// receive data
dIn.readFully(ba_responseBuffer);
}
} catch (IOException ex)
{
ex.printStackTrace();
}
String s_version = new String(ba_responseBuffer);
System.out.println("Version: " + s_version);
s_versionString = s_version;
socket.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
return s_versionString;
}
}

Related

How to receive big files in a server over UDP?

I have to send any size file from a client to a server using UDP. I send the datagrams in byte arrays. I split the file and send the datagrams. I know the server receives the datagrams but my problem is on how to put the datagrams in a File again. This is my code for the Client (I'll just put the code that splits and sends the file, I used JavaFX for the client).
Thank you all in advance.
private void sendFile(ActionEvent event) {
ArrayList<byte[]> listDatagrams;
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
String serverName = "localhost";
InetAddress IPserver;
int serverPort = 6789;
byte[] data;
DatagramPacket request;
IPservidor = InetAddress.getByName(serverName);
data = Files.readAllBytes(file.toPath());
listDatagrams = splitFile(data);
for(byte[] datagrama : listDatagrams){
request= new DatagramPacket(datagrama, datagrama.length, IPserver, serverPort );
socket.send(request);
}
try {
fileOuputStream.write(respuesta.getData());
} finally {
fileOuputStream.close();
}
} catch (SocketException e) {
System.out.println("SocketException: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException: " + e.getMessage());
} finally {
if (socket != null) {
socket.close();
}
}
}
This is the method I used to split the File:
public ArrayList<byte []> splitFile(byte[] file){
ArrayList<byte[]> data = new ArrayList<>();
double nPartitions;
byte[] partition= new byte[MAX];
if(file.length>MAX){
nPartitions =Math.ceil(file.length/MAX);
for(int i=0; i<=nPartitions; i++)
for(int j=0; j<MAX; j++){
if(i==0){
if(j==file.length-1)
break;
partition[j]=file[j];
}else if(i==1){
if((j+MAX)==file.length-1){
break;
}else{
partition[j]=file[(j+MAX)];
}
}else{
if((j+MAX)>=file.length-1)
break;
partition[j]=file[(i*(MAX+1))+j];
}
}
data.add(partition);
}
}
return data;
}
And the code for the server:
public static void main(String args[]) {
DatagramSocket socket = null;
ArrayList<DatagramPacket> data= new ArrayList<>();
try {
int serverPort= 6789;
socket = new DatagramSocket(serverPort);
byte[] buffer;
buffer = new byte[5000];
while (true) {
DatagramPacket request;
request= new DatagramPacket(buffer, buffer.length);
socket.receive(request);
//I add the datagramas to an array list but I am not sure how to re arrenge them into a File. The server should always be on and be able to receive a second file if I want to
data.add(request);
}
} catch (SocketException e) {
System.out.println("SocketException: " + e.getMessage());
} catch (IOException e) {
System.out.println("IOException: " + e.getMessage());
} finally {
if (socket != null) {
socket.close();
}
}
}
Note: I know TCP is better but this is for school so

Java reading from a server on port returns -1

I have to write a socket program to communicate with a server on a given port and DNS. The communication can be a single message or a list of messages; against every message a response is generated from the server. Once a connection is made I receive a response for the first message, but on the next message receive a response of -1. The following is the class handling client server communication:
public class SocketCommunication {
static String[] adresses = null;
final static int port = 1234;
final static int timeout = 60000;
static long pbmId;
private static int count = 0;
private static void loadPBMDNS()
{
DynamicQuery pbmQuery = PH_PBM_SwitchLocalServiceUtil.dynamicQuery();
pbmQuery.add(RestrictionsFactoryUtil.eq("Activated", true));
try
{
List<PH_PBM_Switch> pbmList = PH_PBM_SwitchLocalServiceUtil.dynamicQuery(pbmQuery);
if(pbmList != null && pbmList.size() > 0)
{
if(pbmList.get(0).getServer_DNS() != null
&& !pbmList.get(0).getServer_DNS().equals(""))
{
pbmId = pbmList.get(0).getPBM_Switch_Id();
if(pbmList.get(0).getServer_DNS().contains(";"))
{
String[] tokens = pbmList.get(0).getServer_DNS().split(";");
System.out.println(tokens.toString());
adresses = tokens;
}
else
{
adresses[0] = pbmList.get(0).getServer_DNS();
}
}
}
}
catch (SystemException e)
{
e.printStackTrace();
}
}
public static ArrayList<BatchClaimVO> ConnectSendAndReadResponse
(int addressNumber, ArrayList<BatchClaimVO> batchClaimVOs)
{
try
{
loadPBMDNS();
System.out.println("Connecting to " + adresses[addressNumber] + " on port " + port);
SocketFactory sslsocketfactory = SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket();
sslsocket.connect(new InetSocketAddress(adresses[addressNumber], port), timeout);
System.out.println("Just connected to " + sslsocket.getRemoteSocketAddress());
for (int i = count; i < batchClaimVOs.size(); i++)
{
sendClaim(
sslsocket,
batchClaimVOs.get(i).getCb(),
batchClaimVOs.get(i).getUniqueIdentifier()
);
if(addressNumber <= 2)
{
batchClaimVOs.get(i).setResponse
(readResponse(sslsocket, addressNumber, batchClaimVOs.get(i).getCb()));
}
}
System.out.println("Closing socket");
count = 0;
sslsocket.close();
return batchClaimVOs;
}
catch (IOException e)
{
if(addressNumber < 2)
{
System.out.println("connection timedout trying again on new DNS");
ConnectSendAndReadResponse(++addressNumber, batchClaimVOs);
}
else
{
System.out.println
("unable to connect to server or server did not responed intime");
e.printStackTrace();
}
}
return null;
}
public static void sendClaim(SSLSocket sslSocket, ClaimBuilder cb, long uniqueIdentifier)
throws IOException
{
System.out.println("sending claim");
OutputStream outToServer = sslSocket.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeBytes(cb.getClaim());
System.out.println("claim sent");
SaveRequestLog(uniqueIdentifier, cb.getClaim(), pbmId);
}
public static void SaveRequestLog(long uniqueIdentifier, String claim, long pbmId)
{
if(uniqueIdentifier > 0)
{
try
{
PH_Request_Transaction_Log log = PH_Request_Transaction_LogLocalServiceUtil.getPH_Request_Transaction_Log(uniqueIdentifier);
log.setPBM_Switch_Id(pbmId);
log.setRequest_Log(claim);
log.setCreated_By(LiferayFacesContext.getInstance().getUserId());
log.setCreated_Date(Calendar.getInstance().getTime());
PH_Request_Transaction_LogLocalServiceUtil.updatePH_Request_Transaction_Log(log);
}
catch (PortalException e)
{
e.printStackTrace();
}
catch (SystemException e)
{
e.printStackTrace();
}
}
}
public static String readResponse(SSLSocket sslSocket, int addressNumber, ClaimBuilder cb)
throws IOException
{
sslSocket.setSoTimeout(timeout);
InputStream inFromServer = sslSocket.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
byte[] data = new byte[1048];
int count = in.read(data);
System.out.println(count);
System.out.println(new String(data));
String response = fixString(new String(data), count);
System.out.println("Verifying checksum");
if(verifyTransmissionCheckSum(response))
{
System.out.println("checksum verified");
System.out.println(response);
}
else
{
System.out.println("transmission corrupted");
}
sendAcknowledgement(sslSocket, cb);
return response;
}
public static void sendAcknowledgement(SSLSocket sslSocket, ClaimBuilder cb)
throws IOException
{
System.out.println("sending Acknowledgement");
OutputStream outToServer = sslSocket.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeBytes(cb.buildClaimAcknowledgement());
System.out.println("Acknowledgement Sent");
count++;
}
public static String fixString(String toFix, int count)
{
return toFix.substring(0, count);
}
public static boolean verifyTransmissionCheckSum(String str)
{
return (Integer.parseInt((String) str.subSequence(0, 4))
== (str.subSequence(4, str.length())).length())
? true : false;
}
}
The given server do not support batch communication.

Coding a MultiThreaded Socket Proxy: IOException SocketClosed where it shouldn't

I just started coding a proxy for TCP Socket Connections and although i'm checking if the Sockets are still open i'm getting a IOException.
This is the LOC which is causing it. Anybody has an idea why this can happen?
while (!from.isClosed() && !to.isClosed() && (numOfBytes = in.read(byteBuffer)) != -1)
I've already debugged the code; from & to are not closed when they are checked.
for context:
Proxy.java
public class Proxy
{
public static void main(String[] args)
{
try (ServerSocket proxyServer = new ServerSocket(5432))
{
int i = 0;
while (true)
{
Socket client = proxyServer.accept();
System.out.println(i++);
Socket server = new Socket("localhost", 5000);
ProxyHandler clientToServer = new ProxyHandler(client, server);
ProxyHandler serverToClient = new ProxyHandler(server, client);
clientToServer.setName("client->server"+i);
serverToClient.setName("server->client"+i);
clientToServer.start();
serverToClient.start();
System.out.println("proxy started");
}
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ProxyHandler.java
public class ProxyHandler extends Thread
{
private Socket from;
private Socket to;
public ProxyHandler(Socket from, Socket to)
{
this.from = from;
this.to = to;
}
#Override
public void run()
{
try (DataInputStream in = new DataInputStream(from.getInputStream());
DataOutputStream out = new DataOutputStream(to.getOutputStream()))
{
byte[] byteBuffer = new byte[1024];
int numOfBytes = 0;
while (!from.isClosed() && !to.isClosed() && (numOfBytes = in.read(byteBuffer)) != -1)
{
out.write(byteBuffer, 0, numOfBytes);
out.flush();
System.out.println(getName() + "(" + numOfBytes + ") ");
System.out.println(new String(byteBuffer, "UTF-8"));
}
System.out.println("left : " + getName());
}
catch (IOException io)
{
System.out.println("IOException: " + io.getMessage() + " " + getName());
io.printStackTrace();
}
}
}
isClosed() only returns true if you, yourself, have explicitly closed the socket. It can not be used to detect unexpected disconnects.

DatagramSocket will randomly stop receiving packets (still receives sometimes)

I am trying to implement a TFTP client in Java. The client works perfectly on Localhost and will sometimes work sending to a TFTP server over the network. However, sometimes my DatagramSocket will randomly stop receiving packets. It will send a read/write request but it never receives the next message the server tries to send back. I've checked Wireshark, and the server is for sure receiving and trying to send. And firewalls are turned off where the need to be. Can't figure out what the problem is. Here is the code I am using:
public class TFTPClient {
String filename;
String mode;
boolean read;
PacketBuilder builder;
String IP;
JFrame frame;
public TFTPClient(String uifilename, String uimode, boolean uiread, String uiIP, JFrame uiFrame){
this.filename = uifilename;
this.read = uiread;
this.mode = uimode;
this.IP = uiIP;
builder = new PacketBuilder();
this.frame = uiFrame;
}
/*
* Method choses between reading a file and writing a file based on boolean selected in main UI.
*/
public void startTFTP() throws IOException{
if (read){
readFile();
}
else{
writeFile();
}
}
/*
* Method is used for writing a file
*/
private void writeFile() throws IOException{
byte[] WRQ = builder.getWRQ(filename,mode);
String filenameAndExtension = filename;
RandomAccessFile f = new RandomAccessFile(filenameAndExtension, "r");
byte[] fileBytes = new byte[(int)f.length()];
f.read(fileBytes);
f.close();
DatagramSocket TFTPSocket = new DatagramSocket();
TFTPSocket.setSoTimeout(5000);
//create the packet and send to port 69 of the given IP
DatagramPacket wrqPacket = new DatagramPacket(WRQ, WRQ.length,
InetAddress.getByName(IP), 69);
try {
TFTPSocket.send(wrqPacket);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
byte[] ackByte = new byte[4];
DatagramPacket ackPacket = new DatagramPacket(ackByte,
ackByte.length);
int blockNumber = 0;
DatagramPacket dataPacket;
boolean terminateOnNextAck = false;
boolean needExtraDataPacket = false;
int currentIndex = 0;
while(true)
{
TFTPSocket.receive(ackPacket);
System.out.println("Server acked " + ackByte[3]);
System.out.println("Expected ack " + blockNumber);
blockNumber++;
if(terminateOnNextAck){
break;
}
byte[]DATAdata;
if (needExtraDataPacket){
DATAdata = new byte[0];
terminateOnNextAck = true;
}
else if (currentIndex + 512 > fileBytes.length){
//This is our last byte. Length will be smaller than 508
DATAdata = new byte [fileBytes.length - currentIndex];
terminateOnNextAck = true;
}
else{
DATAdata = new byte[512];
}
if (currentIndex + 512 ==fileBytes.length){
needExtraDataPacket = true;
}
for (int i = 0; i<DATAdata.length; i++){
DATAdata[i] = fileBytes[currentIndex];
currentIndex++;
}
byte[] DATA = builder.getData(DATAdata, blockNumber);
dataPacket = new DatagramPacket(DATA, DATA.length,
InetAddress.getByName(IP),ackPacket.getPort());
try {
TFTPSocket.send(dataPacket);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
TFTPSocket.close();
System.out.println("Write sucessful");
}
/*
* Method is used for reading a file
*/
private void readFile() throws IOException{
//Get RRQ packet
byte[] RRQ = builder.getRRQ(filename,mode);
StringBuffer fileText = new StringBuffer();
DatagramSocket TFTPSocket = new DatagramSocket();
TFTPSocket.setSoTimeout(5000);
//create the packet and send to port 69 of the given IP
DatagramPacket rrqPacket = new DatagramPacket(RRQ, RRQ.length,
InetAddress.getByName(IP), 69);
try {
TFTPSocket.send(rrqPacket);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
byte[] dataByte = new byte[516];
for (int i = 516;i<516;i++){
dataByte[i] = 0;
}
DatagramPacket dataPacket = new DatagramPacket(dataByte,
dataByte.length);
System.out.println("Client: Waiting for packet.");
DatagramPacket ackPacket;
boolean error = false;
while(true)
{
TFTPSocket.receive(dataPacket);
System.out.println(TFTPSocket.getLocalPort());
if (dataByte[1] == 5){
error = true;
break;
}
fileText.append(new String(dataPacket.getData(),0,dataPacket.getLength()));
byte blockNumbers[] = new byte[2];
blockNumbers[0] = dataByte[2];
blockNumbers[1] = dataByte[3];
byte[] ACK = builder.getACK(blockNumbers);
ackPacket = new DatagramPacket(ACK, ACK.length,
InetAddress.getByName(IP),dataPacket.getPort());
try {
TFTPSocket.send(ackPacket);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
if (dataByte[515] == 0){
break;
}
dataByte[515] = 0;
}
if (!error){
JOptionPane.showMessageDialog(frame, "Read Successful!");
System.out.println(fileText);
}
else{
JOptionPane.showMessageDialog(frame,"Error from server: " + new String(dataPacket.getData(),0,dataPacket.getLength()));
}
}
}
The issue turned out to be something with Mac OS X. The program runs fine on Windows. Not entirely sure why, though.

Java Server Sockets: My Server Socket only allows client connections running on the same internet connection?

Ok so I have constructed a working example of a client and server which can accept multiple client connections. My problem is is that I cannot connect a client which is not running the same internet connection as the one the server is being hosted on. Is this possible using server sockets?
Here is the code for my server:
import java.io.IOException;
import java.net.*;
public class MultipleSocketServer {
public static Socket connection;
public static String name = "Tyler's Server";
public static int limit = 2;
public static Thread[] clients = new Thread[limit];
public static int current = 0;
public static int port = 25565;
public static String[] connected = new String[limit];
public static ServerSocket socket;
public static void main(String[] args) {
System.out.println("Server starting...");
for(int i = 0; i < limit; i++) {
connected[i] = "";
}
try {
ServerSocket socket = new ServerSocket(port);
while(true) {
Socket connection = socket.accept();
String ip = connection.getRemoteSocketAddress().toString().substring(1, 13);
loop:
for(int i = 0; i < connected.length; i++) {
if(connected[0].equals(ip) || connected[1].equals(ip)) {
break loop;
}else if(!connected[i].equals(ip)) {
connected[i] = ip;
MultiServer_Client client = new MultiServer_Client(connection, i);
Thread run = new Thread(client);
run.start();
break loop;
}
}
}
} catch (IOException e1) {
System.out.println("Could not bind server on: " + port);
System.exit(-1);
}
}
}
And here is the rest:
import java.io.*;
import java.net.Socket;
public class MultiServer_Client implements Runnable {
public String time;
public Socket client;
public StringBuffer process = new StringBuffer();
public BufferedInputStream inputStream;
public InputStreamReader reader;
public BufferedOutputStream outputStream;
public OutputStreamWriter writer;
public StringVis check = new StringVis("");
public StringChangeListener checkListener = new StringChangeListener() {
public void textChanged(StringChangeEvent e) {
System.out.println("Changed");
write("Server recieved message...");
}
};
public boolean connected = true;
public int ID;
public MultiServer_Client(Socket connection, int i) {
client = connection;
ID = i;
try {
//declare text input/output
inputStream = new BufferedInputStream(client.getInputStream());
reader = new InputStreamReader(inputStream);
outputStream = new BufferedOutputStream(client.getOutputStream());
writer = new OutputStreamWriter(outputStream, "US-ASCII");
} catch (IOException e) {
System.out.println("IOException: " + e);
}
System.out.println(MultipleSocketServer.connected[ID] + " connected...");
write("Connected to " + MultipleSocketServer.name);
}
public void run() {
while(connected) {
read();
}
System.out.println("Disconnecting client...");
}
public void write(String authen) {
try {
time = new java.util.Date().toString();
String message = time + ": " + authen + (char) 13;
writer.write(message);
writer.flush();
} catch (IOException e) {
connected = false;
MultipleSocketServer.connected[ID] = "";
}
}
public void read() {
//read from client
int character;
process = new StringBuffer();
try {
while ((character = reader.read()) != 13) {
process.append((char) character);
}
check.setText(process.toString());
process.delete(0, process.length());
} catch (IOException e) {
connected = false;
MultipleSocketServer.connected[ID] = "";
}
}
}
Here's the client code:
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class SocketClient {
public static String host = "69.182.134.79";
public static int port = 25565;
public static void main(String [] args) {
StringBuffer imports = new StringBuffer();
String time;
System.out.println("Client starting...");
try {
//establish client
InetAddress address = InetAddress.getByName(host);
Socket connection = new Socket(address, port);
BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");
while(true) {
Scanner scan = new Scanner(System.in);
String message = scan.nextLine();
//write to server
time = new java.util.Date().toString();
String process = host + ":" + port + " sent data at " + time + ": " + message + (char) 13;
osw.write(process);
osw.flush();
//read from server
int c;
while ((c = isr.read()) != 13) {
imports.append((char) c);
}
System.out.println(imports);
imports.replace(0, imports.length(), "");
if(message.equals("--EXIT")) {
connection.close();
}
}
} catch (UnknownHostException e) {
System.out.println("UnknownHostException: " + e);
} catch (IOException e) {
System.out.println("IOExcepion: " + e);
}
}
}
Change
MultiServer_Client client = new MultiServer_Client(connection, i);
to
MultiServer_Client client = new MultiServer_Client(new Socket([Server IP], port), i);
This should work.

Categories