I am trying to send int value, long value, long array and 2d double array via socket from the Client to the Server.
I successfully sent int, long values and long array, however when it comes to the double array (output.writeObject(server_ind); - see Client Side code below), I am getting the following error:
ERROR:
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1876)
at java.io.ObjectOutputStream$BlockDataOutputStream.writeByte(ObjectOutputStream.java:1914)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1575)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:350)
at clientSide.ClientSocket.connectionProtocol(ClientSocket.java:36)
at clientSide.clientMain.main(clientMain.java:97)
My code is the following:
Client Side:
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(num_doc); //int value
output.flush();
output.writeObject(num); //long value
output.flush();
output.writeObject(queryTDs); //long[] array
output.flush();
output.writeObject(server_ind); //double[][]
output.flush();
Server Side:
input = new ObjectInputStream(clientSocket.getInputStream());
num_doc = input.readInt();
num = input.readLong();
TDs = (long[]) input.readObject();
server_ind = (double[][]) input.readObject();
output = new ObjectOutputStream(clientSocket.getOutputStream());
output.writeObject("Received");
Thanks!
The Broken pipe Exception happen when the connection between sender and receiver is closed by reciver (in this case the Server Side) before the sender finish to send all the stream.
Checking your code i notice that:
In the first case, you are sending and object of 32 bits (int):
output.writeObject(num_doc); //int value
output.flush();
And wait for 32 bits:
num_doc = input.readInt();
The same for the second case, when you send and recived 64 bits (long type)
In the case of an long[] you are sending an Object wich its size depends of the amount and type of the data, according whith oracle documentation, for `ObjectOutputStream:
Write the specified object to the ObjectOutputStream. The class of the object, the signature of the class, and the values of the non-transient and non-static fields of the class and all of its supertypes are written
But in the case of double[][], you are sending an (double[]) that each element has another double[]. For some reason, that is not clear for me, the ObjectInputStream is not able to read all the objects that had been sended by your client.
So, it could be that the receiver doesn't know how many byte need to read to build the double array.
One question for you (#Liutauras94): Is there a exception in the server side?
I recomend you to convert the double value to an array of 4 bytes (64 bits) and send it with a method write(byte[]) instead of writeObject. Be aweare of the order of byte that recive the other part.
Also, in Java, there are another kind of stream writers that handle numeric data types, they are better than try to send an object.
You're writing objects but reading primitives. So eventually you read less data than is really there, not to mention entirely wrong data; then you close the socket while there is still unread pending data in it; and that causes a connection reset to be propagated to the writer; which causes the 'broken pipe'.
If you write data with writeObject() you must read it with readObject(). If you write data with writeInt() you must read it with readInt(). And so on.
Related
I'm trying to create application that will send object through local network using Sockets. When i run server and client code in Intellij Idea they work fine, but when i run server code on one pc and client code on another pc i get errors like java.io.StreamCorruptedException: invalid type code: 00 or java.io.StreamCorruptedException: invalid stream header: 6C69656E
byte[] readBuffer = new byte[4096];
int num = inStream.read(readBuffer); //inStream is socket input stream
ByteArrayInputStream bis = new ByteArrayInputStream(readBuffer);
ObjectInput in = new ObjectInputStream(bis);
Object o = in.readObject(); //this line throws error
The thing is that writing and reading object to socket stream works on server (which is on pc where i created project) but reading from input stream on client (another pc where i copied project) throws error.
Can someone help me with this? I searched everywhere for solution but i can't figure out what is problem with serializing, because it works on same pc but won't on another. Is there any way that i can make this pc independent? This also happens when i create jar files and run it on same pc where it works in Intellij Idea.
It can because that client didnt read message fully.
But the real mistake is that you work with TCP socket like a message protocol transport but TCP is a stream protocol so you have to create your own message protocol on top of TCP.
Why it works fine on local system?
Because transport data between client and server happen too fast in local test and maybe in just one frame so all the message transported in just one IO-call but in internet or a network it doesn't work like you think.
There is 2 way to handle this mistake:
1- Pass SocketInputStream directly to ObjectInputStream instance and let it handle read objects.
2- Create a message protocol for example you can put the size of message in 2 or more first bytes. Then you can workd like this :
Read 2(or more) first bytes and detect size of packet.
Create a buffer for this size and read packet bytes.(make sure you read all of packet data from socket . You can use return value of SocketInputStream.read(byte[]) method to calculate it)
Pass the packet to ObjectInputStream and read object !
I have a Socket connection to an application that I hosted elsewhere. Once I connected I made a OutputStream and DataInputStream.
Once the connection has been made, I use the OutputStream to send out a handshake packet to the application. Once this handshake has been approved, it returns a packet through the DataInputStream (1).
This packet is processed and is returned to the application with the OutputStream.
If this returned data is valid, I get another packet from the DataInputStream (2). However, I have not been able to read this packet through the DataInputStream.
I have tried to use DataInputStream.markSupported() and DataInputStream.mark() but this gave me nothing (except for an empty Exception message).
Is it possible to read the input stream for a second time? And if so, can someone please point me out what I'm doing wrong here?
EDIT: Here is my solution:
// First define the Output and Input streams.
OutputStream output = socket.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// Send the first packet to the application.
output.write("test"); // (not actual data that I sent)
// Make an empty byte array and fill it with the first response from the application.
byte[] incoming = new byte[200];
bis.read(incoming); //First packet receive
//Send a second packet to the application.
output.write("test2"); // (not actual data that I sent)
// Mark the Input stream to the length of the first response and reset the stream.
bis.mark(incoming.length);
bis.reset();
// Create a second empty byte array and fill it with the second response from the application.
byte[] incoming2 = new byte[200];
bis.read(incoming2);
I'm not sure if this is the most correct way to do this, but this way it worked for me.
I would use ByteArrayInput stream or something that you can reset. That would involve reading the data into another type of input stream and then creating one.
InputStream has a markSupported() method that you could check on the original and the byte array one to find one that the mark will work with:
https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#markSupported()
https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html
The problem here is not re-reading the input. I don't see anything in the question that requires you to read the input twice. The problem is the BufferedInputStream, which will read everything that is available to be read, including the second message, if it has already arrived.
The solution is not to use a buffered stream until you have completed the handshake. Just issue a read on the socket input stream for exactly the length of the first message, do the handshake, and then proceed to construct and read the buffered stream.
I'm working on implementing a RCON for Minecraft, which uses the Valve rcon protocol, and I've gotten my hands on the C source and tried to implement it into Java, this is what I've done so far:
Creating the packet:
http://pastebin.com/9AeiSQPD
Recieve the packet: http://pastebin.com/n6V1KnPa
Send the packet: http://pastebin.com/rixhD15p
I'm sending the AUTH packet to the server and trying to receive a response, but the return value is null, also trying to send a command throws:
Software caused connection abort: socket write error
What am I doing wrong?
I think there are two wrong things in your code.
1) First as you can see here the packet structure use 4 bytes blocks (32bits) of little-endian integer. The means reverse blocks (see here).
2) Second you didnt use null block (empty String or null character) at end of packet.
Solution:
1) Use: (ByteBuffer and ByteOrder are from native java.nio java7)
writer.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN)
.putInt(p.size).array());
writer.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN)
.putInt(p.id).array());
writer.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN)
.putInt(p.cmd).array());
Instead of:
writer.writeInt(p.size);
writer.writeInt(p.id);
writer.writeInt(p.cmd);
and:
ByteBuffer.wrap(<4_BLOCKS_BYTES>)
.order(ByteOrder.LITTLE_ENDIAN).getInt();
instead of:
reader.readInt();
where <4_BLOCKS_BYTES> is a bytes array of size 4, read from the reader.
And if I can give you an advice, it can be easier (I think) to use a global buffer to send.
I mean a buffer containing size, id, type, data and empty block as bytes. And same thing when you read response: use a buffer to read while the DataInputStream is available() and then parse it.
Good luck!
Java Doc links:
java.nio: docs.oracle.com/javase/7/docs/api/java/nio/package-frame.html
DataInputStream.available(): docs.oracle.com/javase/7/docs/api/java/io/FilterInputStream.html#available()
In my server-side code I need to be able to listen to a socket to exchange JSON 'packets' with a Java 7 test application on the same machine. The connection is made and a JSON string is constructed and written to the socket by the Java test application. It is received by the Dart server-side application and passed to a callback method, handleJson, which attempts to decode it. The process dies on 'JSON.decode'.
I think it dies because the string is prepended, by the Java 'writeUTF' method with a short int that contains the number of bytes in the JSON UTF-8 uncluding the leading short and the leading byte is 0.
Is there a Dart method to handle this, in each direction, or must I write the code? (I had thought that JSON work easily between languages.)
The JSON string before writing to the socket in my Java test application:
{"target":"DOOR","command":"OPEN"} // 34 characters
A Java snippet:
// in a try-catch
Socket client = new Socket(serverName, port);
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF(json);
client.close();
The Java documentation states that the out.writeUTF method converts the json string to UTF-8 with the string length prepended as a short int containing the total number of bytes written.
In main:
ServerSocket.bind('127.0.0.1', 4041)
.then((serverSocket) {
print('connected');
// prints: 'connected'
serverSocket.listen((socket) {
socket.transform(UTF8.decoder).listen(handleJson);
});
});
handleJson method:
handleJson(String stringAsJson){
print('string length is ' + (stringAsJson.length).toString());
// prints: 'string length is 36'
print('received json $stringAsJson');
// prints: 'received json '
String json = JSON.decode(stringAsJson);
// dies on decode
print('Sever Socket received: $json');
}
This will give you some troubles, since Socket is raw TCP, and TCP is streaming. That means that the text (bytes) you send can be split and merged in any way the network may find suitable.
In your case, you need a way to mark the end of each JSON message. An example could be to accumulate all bytes received, until the byte 0 is seen (invalid in JSON). Those bytes could then be converted to UTF8 and then again converted to JSON. Note that the peer needs to send this 0 byte in between messages, for this to work.
Now, you also consider using WebSockets as a way to sent messages. After the initial HTTP handshake, it's actually just a raw TCP socket with some extra header information, to make it package oriented - exactly what you need. dart:io already includes a WebSocket implementation.
My problem is that C sockets look to act differently than Java sockets. I have a C proxy and I tested it between a workload generator (oltp benchmark client written in Java) and the JDBC connector of the Postgres DB.
This works great and forwards data from one to other, as it should. We need to make this proxy work in Java, so I used plain ServerSocket and Socket classes from java.net and I cannot make it work. The Postgres returns an authentication error message, assuming that the client did not send the correct password.
Here is how the authentication at the JDBC protocol works:
-client sends a requests to connect to a database specifying the database name and the username
-server responds back with a one time challenge message (13 byte message with random content)
-client concatenates this message with the user password and performs a md5 hash
-server compares the hash got from the client with the hash he computes
[This procedure is performed in order to avoid replay attacks (if client would send only the md5 hash of its password then an attacker could replay this message, pretending he is the client)]
So I inspected the packets with tcpdump and they look correct! The size is exactly as it should, so maybe the content is corrupted (??)
Sometimes though the DB server responds ok for the authentication (depending on the value of the challenge message)!! And then the oltp client sends a couple of queries, but it crashes in a while…
I guess that maybe it has to do with the encoding, so I tried with the encoding that C uses (US-ANSII), but still the same.
I send the data using fixed size character or byte arrays both in C and in Java!
I really don't have any more ideas, as I tried so many cases...
What is your guess of what would be the problem?
Here is a representative code that may help you have a more clear view:
byte [] msgBuf;
char [] msgBufChars;
while(fromInputReader.ready()){
msgBuf = new byte[1024];
msgBufChars = new char[1024];
// read data from one party
int read = fromInputReader.read(msgBufChars, 0, 1024);
System.out.println("Read returned : " + read);
for(int i=0; i<1024; i++)
msgBuf[i] = (byte) msgBufChars[i];
String messageRead = new String(msgBufChars);
String messageToWrite = new String(msgBuf);
System.out.println("message read : "+messageRead);
System.out.println("message to write : "+new String(messageToWrite));
// immediatelly write data to other party (write the amount of data we read (read value) )
// there is no write method that takes a char [] as a parameter, so pass a byte []
toDataOutputStream.write(msgBuf, 0, read);
toDataOutputStream.flush();
}
There are a couple of message exchanges in the beginning and then Postgres responds with an authentication failure message.
Thanks for your time!
What is your guess of what would be the problem?
It is nothing to do with C versus Java sockets. It is everything to do with bad Java code.
I can see some problems:
You are using a Reader in what should be a binary stream. This is going to result in the data being converted from bytes (from the JDBC client) to characters and then back to bytes. Depending on the character set used by the reader, this is likely to be destructive.
You should use plain, unadorned1 input streams for both reading and writing, and you should read / write to / from a preallocated byte[].
This is terrible:
for(int i=0; i<1024; i++)
msgBuf[i] = (byte) msgBufChars[i];
If the characters you read are not in the range 0 ... 255 you are mangling them when you stuff them into msgBuf.
You are assuming that you actually got 1024 characters.
You are using the ready() method to decide when to stop reading stuff. This is almost certainly wrong. Read the javadoc for that method (and think about it) and you should understand why it is wrong. (Hint: what happens if the proxy can read faster than the client can deliver?)
You should use a while(true), and then break out of the loop if read tells you it has reached the end of stream; i.e. if it returns -1 ...
1 - Just use the stream objects that the Socket API provides. DataXxxStream is unnecessary because the read and write methods are simply call-throughs. I wouldn't even use BufferedXxxStream wrappers in this case, because you are already doing your own buffering using the byte array.
Here's how I'd write that code:
byte [] buffer = new byte[1024]; // or bigger
while(true) {
int nosRead = inputStream.read(buffer);
if (nosRead < 0) {
break;
}
// Note that this is a bit dodgy, given that the data you are converting is
// binary. However, if the purpose is to see what embedded character data
// looks like, and if the proxy's charset matches the text charset used by
// the client-side JDBC driver for encoding data, this should achieve that.
System.out.println("Read returned : " + nosRead);
System.out.println("message read : " + new String(buffer, 0, nosRead));
outputStream.write(buffer, 0, nosRead);
outputStream.flush();
}
C sockets look to act differently than Java sockets.
Impossible. Java sockets are just a very thin layer over C sockets. You're on the wrong track with this line of thinking.
byte [] msgBuf;
char [] msgBufChars;
Why are you reading chars when you want to write bytes? Don't use Readers unless you know that the input is text.
And don't call ready(). There are very few correct uses, and this isn't one of them. Just block.