How do I read a Json from a socket? Java - java

I am doing a Server/Client network. The messages are send as Json Objects.
I have a method for writing the Json-Object but my method for reading the Json-Object doesnt work. I dont have any exceptions but there is no output like excpected. Something must be wrong with the bufferedReader. I dont know how to get that Json-Object from the socket who sent it.
Method for writing:
public void writeMessage(JSONObject json) {
try {
PrintWriter printWriter = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream()));
printWriter.print(json);
printWriter.flush();
} catch (IOException writeMessageException) {
System.out.println("!");
}
}
method for reading the message/ receiving the message:
private static void readMessageFromServer(Socket socket) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())))
{
StringBuilder sb = new StringBuilder();
String readLine;
while ((readLine = br.readLine()) != null) {
sb.append(readLine);
}
JSONObject js = new JSONObject(sb.toString());
String action1 = (String) js.get("action1");
System.out.println(action1);
} catch(IOException e) {
System.out.println("!");
}
}
Thank you :)

Consider using javax websocket.
javax.websocket client simple example
You can simply implement MessageHandler and specify the type parameter you expecting to receive using POJOs.
#Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<MyJsonObject>() {
#Override
public void onMessage(MyJsonObject message) {
//do something
}
});
}
That way you are creating a listener (#OnMessage) and handling each message as soon as it received. You can also implement MessageHandler with String type parameter and handle parsing the json yourself inside OnMessage method;
#Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
MyJsonObject jObj = new ObjectMapper().readValue(message, MyJsonObject.class);
}
});
}
If you want to stick with java net socket consider switching to Jackson Object Mapper from JSONObject, that way you can convert input stream into any object:
private static void readMessageFromServer(Socket socket){
InputStream in = socket.getInputStream();
MyObject obj = new ObjectMapper().readValue(in, MyObject.class);
}
more javax webSocket examples

When reading data in bytes, we need to define our own protocol for communication between server and client. The simplest protocol which
we can define is called TLV (Type Length Value). It means that every
*message written to the socket is in the form *of the Type Length Value.
So we define every message sent as:
A 1 byte character that represents the data type, like s for String A
4 byte integer that indicates the length to the data And then the
actual data, whose length was just indicated
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
char dataType = in.readChar();
int length = in.readInt();
if(dataType == 's') {
byte[] messageByte = new byte[length];
boolean end = false;
StringBuilder dataString = new StringBuilder(length);
int totalBytesRead = 0;
while(!end) {
int currentBytesRead = in.read(messageByte);
totalBytesRead = currentBytesRead + totalBytesRead;
if(totalBytesRead <= length) {
dataString
.append(new String(messageByte, 0, currentBytesRead, StandardCharsets.UTF_8));
} else {
dataString
.append(new String(messageByte, 0, length - totalBytesRead + currentBytesRead,
StandardCharsets.UTF_8));
}
if(dataString.length()>=length) {
end = true;
}
}
}
More detail info can be found here
https://www.baeldung.com/java-inputstream-server-socket

Related

Java ObjectInputStream throws EOFException with bigger object

I have this method to deserialize:
public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
Object res = is.readObject();
is.close();
in.close();
return res;
}
and this one to serialize:
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
byte[] res = out.toByteArray();
out.close();
os.close();
return res;
}
I use these methods to serialize and deserialize a class object, that only has a string and an arrayList of another class, exchanged between 2 devices. Both the class of the object and the class of the arrayList implement serializable.
When I send an object with up to 3 elements in the arrayList these methods work perfectly. However, when the arrayList has 4 or more elements, the device receiving the object still detects that some data has "arrived" but the deserialize method generates an "EOFException" in the "Object res = is.readObject();" line.
Any ideas about what the problem could be ?
EDIT
This is the class of the arrayList:
import java.io.Serializable;
public class Info implements Serializable {
public Info() {
...
}
...
}
This is the class of the object:
import java.io.Serializable;
import java.util.ArrayList;
public class BluetoothDataContainer implements Serializable{
private ArrayList<Info> dataList;
private String originDevice;
public BluetoothDataContainer(String originDevice){
dataList= new ArrayList<Info>();
this.originDevice = originDevice;
}
...
}
This is the code I use to send the object:
BluetoothDataContainer data = new BluetoothDataContainer(mBluetoothAdapter.getName());
...
// add needed info to variable 'data'
...
s.write(data);
Where 's' is a thread with the method 'write':
private BluetoothSocket mmSocket = bluetoothDevice.createRfcommSocketToServiceRecord(ID_CONNECTION);
private OutputStream mmOutStream = mmSocket.getOutputStream();
...
public void write(BluetoothDataContainer m) {
try {
mmOutStream.write(serialize(m));
} catch (IOException e) {
this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - write() !");
}
//cancel();
this.interrupt();
}
And this is how I handle the object when it is read:
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
final BluetoothDataContainer data;
try {
data = (BluetoothDataContainer) deserialize(readBuf);
...
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
And this is how I read the object:
private final Handler mHandler; // value set in the constructor
...
public void run() {
mmInStream = bluetoothSocket.getInputStream();
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes;
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
this.mContext.showToast("ConnectedThread [Bluetooth connection handler] data received !");
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(1, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - run() !");
}
}
Clearly you have not 'exchanged' the entire byte array in the case that fails.
bytes = mmInStream.read(buffer);
You can't possibly know from this alone whether you've read:
an entire message
less than one message
more than one message.
As you already have a socket with input and output streams, it beats me why you are creating byte arrays at all. Just wrap the ObjectOutputStream around the socket output stream and use writeObject(). At the receiver, wrap the ObjectInputStream around the socket input stream and use readObject().
NB you should use the same object streams for the life of the socket, and if you are sending objects both ways you must create the object output stream before the object input stream for the same socket: otherwise you can get a deadlock.

How to set a timeout on a BufferedReader with a socket stream

Here I am creating a thread to check for a server response every 2 seconds, the issue is that the client.monitorResponse() is a readLine() method and will not continue until a response is received.
client = new ClientObject("localhost");
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
String response = null;
if(!(response = client.monitorResponse()).isEmpty()) {
System.out.println("Response: " + response);
} catch (Exception e) {
e.printStackTrace();
}
}
}, 2000, 2000);
I am sending the response via the Server like so (where client is a established Socket):
public SocketObject(Socket client, int numberOfClients) throws Exception {
socket = client; // the .accept() socket is passed through
// this is because I assign them ID's for later use (I hold an ArrayList of sockets)
this.clientId = numberOfClients;
// both these are static to the class
outputStream = new PrintWriter(client.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(client.getInputStream()));
}
public void sendResponse(String response) {
outputStream.println(response);
}
I am then picking the response up via the client Socket that has connected to the server:
public ClientObject(String hostname) throws IOException {
// socket is static to this class
socket = new Socket(hostname, 4444);
System.out.println("Connected to " + hostname + " on port 4444...");
// both static to this class
outputStream = new PrintWriter(socket.getOutputStream(), true);
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Successfully started a stream on " + hostname);
this.hostname = hostname;
}
public String monitorResponse() throws Exception {
System.out.println("Listening for a response...");
return inputStream.readLine();
}
The debug console only displays the Listening for a response... output once which is telling me that it doesn't get past the inputStream.readLine() method in-side the Thread. Is there anyway I can add a timeout on the BufferedReader? I have tried multiple solutions like adding a .setSoTimeout() to the socket before creating the BufferedReader but all that did was close the connection/socket after the specified time.
Any help would be appreciated.
You should use a non-blocking (NIO) request and read chunks looking for newlines in-between. Typically in Java you just have to look for the NIO version of the Stream class you are using and use it to check every N seconds for new content. In your case with minimal modifications you can use the less fancy and efficient method of blocking calls with BufferedReader.ready() to prevent blocking:
String partialLine="";
public static String monitorResponse() throws Exception {
System.out.println("Listening for a response...");
int nextByte;
String nextChar;
while (inputStream.ready()) {
nextByte = inputStream.read();
nextChar = Character.toString ((char) nextByte);
partialLine += nextChar;
if ("\n".equals(nextChar)) {
String line = partialLine;
partialLine = "";
return line.replace("\r\n", "");
}
}
return "";
}
Check out http://tutorials.jenkov.com/java-nio/nio-vs-io.html for more info.
Is there anyway I can add a timeout on the BufferedReader?
No, but you can set a timeout on the Socket, with Socket.setSoTimeout().
I have tried multiple solutions like adding a .setSoTimeout() to the socket before creating the BufferedReader but all that did was close the connection/socket after the specified time.
No it doesn't close the socket. It throws SocketTimeoutException, which you should catch and handle as pertinent. If the socket is being closed, you're closing it. Solution: don't.

Restlet Filter Post request

I would like to filter a Post request in Filter (prior it getting to the Resource).
To filter the request I want to retrieve a token from the bode request and do some testing on it.
Current Resource:
#Post
public JsonRepresentation init(JsonRepresentation jRep) {
String token = jRep.getJsonObject().getString("token");
.
.
.
}
Current Filter:
#Override
protected int beforeHandle(Request request, Response response) {
int result = STOP;
String token = (String) Request.getCurrent().getAttributes().get("token");
.
.
.
}
These code does not retrieve the token.
My question is how can I retrieve a body request?
You can directly get the payload text of the request from its associated entity object, as described below:
Representation repr = request.getEntity();
String content = repr.getText();
Hope it helps you,
Thierry
you can try something like this to retreive the body :
public static String getBody(HttpServletRequest request) throws IOException {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
return body;
}
As it is dangerous to store request entities directly into memory (imagine if a client send a tera-bytes representation), the framework does not persist representations into memory by default, they can only be read once (from the socket).
I guess the answers to your issue may be read from here: Restlet reuse InputStream

Sending a request to a server java

I wrote some code for a server and a client to transfer a file from the server to the client and it worked like a charm; however I have few questions. I want to build this code under a GUI, and I want to list all the files on the folder, but how can I make the client choose the file he wants after he see the list of files offered (how can I send a string to the server in order to choose the file)?
Server Code
import java.io.*;
import java.net.*;
class TCPServer {
public static void listfile(){
File folder = new File("c:/");
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
} else if (listOfFiles[i].isDirectory()) {
System.out.println("Directory " + listOfFiles[i].getName());
}
}
}
public static void main(String args[]) {
listfile();
while (true) {
ServerSocket welcomeSocket = null;
Socket connectionSocket = null;
BufferedOutputStream outToClient = null;
try {
welcomeSocket = new ServerSocket(3248);
connectionSocket = welcomeSocket.accept();
outToClient = new BufferedOutputStream(connectionSocket.getOutputStream());
} catch (IOException ex) {
// Do exception handling
}
if (outToClient != null) {
String FileName = "carexception.java";
File myFile = new File("C:\\"+FileName);
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = null;
try {
fis = new FileInputStream(myFile);
} catch (FileNotFoundException ex) {
// Do exception handling
}
BufferedInputStream bis = new BufferedInputStream(fis);
try {
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
outToClient.flush();
outToClient.close();
connectionSocket.close();
// File sent, exit the main method
return;
} catch (IOException ex) {
// Do exception handling
}
}
}
}
}
Client Code
import java.io.*;
import java.net.*;
import java.util.*;
class TCPClient {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
byte[] aByte = new byte[1];
int bytesRead;
Socket clientSocket = null;
InputStream is = null;
try {
clientSocket = new Socket("127.0.0.1", 3248);
is = clientSocket.getInputStream();
} catch (IOException ex) {
// Do exception handling
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (is != null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream("E:\\sss.java");
bos = new BufferedOutputStream(fos);
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
bos.write(baos.toByteArray());
bos.flush();
bos.close();
clientSocket.close();
} catch (IOException ex) {
// Do exception handling
}
}
}
}
To accomplish what you're after you have to change quite a few things.
You can assume a specific protocol order, in the sense that the client needs to send a request to the server in order for the server to do anything, so the server is always in a listening state when the connection has been established.
You should,
Introduce a loop of sending requests and receiving responses
Figure out how to send a string object
Break up the file sending part so you don't allocate larger byte arrays than the OS can hand you (consider a file being 4GB for instance, allocating a byte array for the whole file can be troublesome)
So, with this in mind we can get going. Regarding step 1, this can be accomplished using a while loop. If we assume that the server always listens for a request, the server "request loop" can look something like this.
ClientRequest request;
while (request.getType() != RequestType.Complete) {
// receive new request
// depending on type, send response
}
We simply added two classes here, one ClientRequest that encapsulates a message from the client, and an enum RequestType that defines the type of request the client is interested in, for instance a file list or file contents.
public enum RequestType {
None, Complete, RequestFileList, RequestFileContent
}
public class ClientRequest {
private RequestType type;
public ClientRequest() {
type = RequestType.None;
}
public RequestType getType() {
return type;
}
}
Now we need to attach this to the socket somehow, so we add a method for receiving a request, and assign that request to the current request instance.
ClientRequest request = new ClientRequest();
while (request.getType() != RequestType.Complete) {
// receive new request
receiveRequest(clientSocket.getInputStream(), request);
if (request.getType() != RequestType.Complete) {
// pick a response
}
}
private void receiveRequest(DataInputStream socketStream, ClientRequest request) {
// get a type of request
byte type = socketStream.readByte();
request.setType(RequestType.from(type));
// get parameters for request, depending on type
if (request.getType() == RequestType.RequestFileContent) {
// receive file id (file name for instance, or some other id that you prefer)
String argument = readString(socketStream);
request.setArgument(argument);
}
}
This adds a from method in RequestType, to convert a byte to a request, a setType method in ClientRequest, and a readString method. We also add a new field and corresponding get and set methods in ClientRequest.
public enum RequestType {
// types as before
;
public static RequestType from(byte b) {
switch (b) {
case 1: return RequestType.Complete;
case 2: return RequestType.RequestFileList;
case 3: return RequestType.RequestFileContent;
default: return RequestType.None;
}
}
}
public class ClientRequest {
private String argument;
public void setType(RequestType value) {
type = value;
}
public String getArgument() {
return argument;
}
public void setArgument(String value) {
this.argument = value;
}
}
private String readString(DataInputStream socketStream) {
int length = socketStream.readInt();
byte[] stringBytes = new byte[length];
socketStream.read(stringBytes);
return new String(stringBytes, "UTF-8");
}
Now we get to the next step, responding to the request. Simply add a switch case and handle the type of request.
{
// depending on type, send response
handleRequest(clientSocket.getOutputStream(), request);
}
private void handleRequest(DataOutputStream socketStream, ClientRequest request) {
switch (request.getType()) {
case RequestType.RequestFileList: {
String[] fileList = getFileList(getCurrentDirectory());
// send response type
socketStream.write(ResponseType.ResponseFileList.getByte());
// send number of files
socketStream.writeInt(fileList.length);
// send each string
for (String fileName : fileList) {
sendString(socketStream, fileName);
}
}
break;
case RequestType.RequestFileContent: {
// send response type ResponseType.ResponseFileContent
// send length of file so other party can determine number of bytes to receive
// send file contents in chunks of a fixed byte array length
// send last part of file contents, if length of file is not evenly divided by array chunk size
}
break;
}
}
the sendString method is simply a "reversed order" of the readString method.
private void sendString(DataOutputStream socketStream, String value) {
int length = value.length();
socketStream.writeInt(length);
byte[] stringBytes = value.getBytes("UTF-8");
socketStream.write(stringBytes);
}
The ResponseType is an enum of values similar to the ones in RequestType, so the client can handle the type of response that the server sends.
With these changes, you will be able to request a file list and present the response of files that the server sends. When the user picks a file to receive, the client can send a new request to the server and the server can send the appropriate file contents to the client.
The client application will have to define a similar ClientRequest class (perhaps with the name ServerResponse) with corresponding methods that the server specified for reading from and writing to the socket streams. This can be abstracted further by encapsulating the socket in a class, with a listener pattern for when a request or response is received that the GUI can subscribe to, ..although this goes beyond my example.
If you feel I need to clarify anything, please leave a comment and I'll do my best to answer.
How do you ask files? By name! I think that server accepts commands and responds with responses. You may use the format for your commands to server: CMD_NAME, arg1, arg2, ... Arguments can be binary, dependent on command. By CMD_NAME, your server will distinguish what you want from it (either accept the file or provide one).
You have a problem that you accept only one type of request. You need a command mechanism to ask different requests from server. Server needs to parse those requests rather than give a hardcoded answer immediately. This will make it flexible.
http://www.javamex.com/tutorials/networking/simple_server_s_side.shtml I am sure that there a tons of other examples like this. Java sockets are reliable, there cannot be problem. Just start learning basics, how to communicate different messages between client and server. But, your problem is not Sockets-related at all. Imagine that you communicate over files: read requests from one and write responses into another. Which messages do you write then? This is called a protocol. You need to design a simple one.
Have you tried creating an array, so each file has it own index... When the client chooses the file he wants, then you return the file on certain array index.
~ btw you can serialize your array and send it to the client.
You can use ObjectOutputStream to send Strings or any other kind of Object via writeObject.

How to convert byte[] to String correctly?

I'm building a swing interface in Java, I build a middleware which keeps reading the serial port and saving what's coming to String, here it's how I'm doing this:
public class RFID {
private static RFIDReader rReader;
private static boolean state;
public RFID(RFIDReader rReader) {
this.rReader = rReader;
this.state = true;
}
public void connect(String portName) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
InputStream in = serialPort.getInputStream();
OutputStream out = serialPort.getOutputStream();
(new Thread(new SerialReader(in))).start();
//(new Thread(new SerialWriter(out))).start();
} else {
System.out.println("Error: Only serial ports are handled by this example.");
}
}
}
public static class SerialReader implements Runnable {
InputStream in;
public SerialReader(InputStream in) {
this.in = in;
}
public void run() {
byte[] buffer = new byte[1024];
int len = -1;
String code;
try {
while (state == true && (len = this.in.read(buffer)) > -1) {
code = new String(buffer, 0, len);
if (code.length() > 1)
rReader.setCode(code);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void finish(){
state = false;
}
public static class SerialWriter implements Runnable {
OutputStream out;
public SerialWriter(OutputStream out) {
this.out = out;
}
public void run() {
try {
int c = 0;
while ((c = System.in.read()) > -1) {
this.out.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
So when I try to print what code is storing, it shows like this:
AC000F9
3
BB
What actually should look like this:
AC000F93BB
What am I doing wrong here ? This conversion from byte[] to String is not right ?
EDIT:
I need to read a string with 10 characters at total.
Don't use an InputStream to read from - use a Reader of some description. If you need to start with an InputStream, wrap it in an InputStreamReader. I would change your constructor to accept a Reader though, and allow clients to pass whatever reader they want in. That will make it easier to test (as you can just use a StringReader).
EDIT: Note - if you do need to create a reader from a binary InputStream, be explicit in your choice of Charset (encoding). So use the InputStreamReader constructor overload which specifies one. Even if you want to use the platform default, I'd be explicit about that to make it clear what you're doing.
EDIT: Beyond "where the string conversion happens" it's unclear what you're expecting to read. You're dealing with streaming APIs - what determines how much you really want to read before calling setCode? Is it a whole line? Is it some fixed number of characters? Is it characters before a particular delimiter?
EDIT: Now we know a bit more, I suggest you write a helper method like this:
// Assuming you now have a field of type Reader, called reader
private String readEntry() throws IOException {
char[] buffer = new char[10];
int index = 0;
while (index < buffer.length) {
int charsRead = reader.read(buffer, index, buffer.length - index);
if (charsRead == -1) {
throw new IOException("Couldn't read entry - end of data");
}
index += charsRead;
}
return new String(buffer);
}

Categories