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 :)
CodePudding user response:
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;
}
}
}
CodePudding user response:
- 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