I have a problem with a BufferedOutputStream. I want to send a kml file from an Android device to a java server through a socket connection.
(The connection is ok, i am already able to exchange data with a PrintWriter in an other part of my program)
To send my kml file, I fill the buffer. But when i flush() it, nothing happen.
int lu = inFile.read();
while(lu != -1){
out.write(lu);
lu = inFile.read();
}
out.flush();
inFile.close();
inFile is my stream used to read the kml file
out is my BufferedOutputStream using the OutputStream of my socket
I don't close my out object but i don't want to, i don't use it just once. And this is the problem...
The close() method send the buffer's data but close the socket too.
The flush() method does not send the buffer's data.
I want to flush the buffer without closing my socket.
I also tried to use mySocket.shutdownOutput();
int lu = inFile.read();
while(lu != -1){
out.write(lu);
lu = inFile.read();
}
out.flush();
mySocket.shutdownOutput();
inFile.close();
This method close my stream and keep my socket open, that's what i want.
But when i try to open a new output stream, the Exception java.net.SocketException: Socket output is shutdown
So, how to flush my buffer without closing my sokcet are being unable to open a new output stream ?
Socket.close() and Socket.shutdownOutput() both send an EOS to the peer, on which he should close the socket, and after which you can no longer write to the socket, because you've closed it in that direction.
So if you need to continue writing to the socket you cannot use either of these methods.
Probably what you are searching for is a way to delimit application protocol messages. There are at least three techniques:
Send a length word prior to each message.
Send an out-of-band delimiter after each message, i.e. a byte or byte sequence that cannot occur in a message. The STX/ETX protocol, with escapes, is an example of this.
Use a self-describing message format such as Object Serialization or XML. STX/ETX is also an example of this.
Related
I have been trying to send a byte[] array across my client / server application using Sockets, DataInputStream and DataOutputStream, but on the server side, the program just gets stuck when I try to initialise the DataInputStream.
Here is the code on the client side (it works fine):
DataOutputStream datas = new DataOutputStream(connection.getOutputStream());
datas.flush();
byte[] send = identityKeyPair.serialize();
datas.write(send);
datas.flush();
Here is the code on the server side:
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()) );
sender = new PrintWriter(connection.getOutputStream());
newUser = new BasicUserData();
System.out.println("New registration from: " + connection.getInetAddress());
System.out.println("Data:");
String un = reader.readLine();
newUser.USERNAME = un;
System.out.println(newUser.USERNAME);
String pw = reader.readLine();
newUser.PASSWORD = pw;
System.out.println(newUser.PASSWORD);
DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
System.out.println("Opened data output stream");
DataInputStream receiver = new DataInputStream(connection.getInputStream());
//It gets stuck here, and the program doesn't read anything further
receiver.read();
byte[] id = receiver.readAllBytes();
System.out.println("Opened data input stream");
You are using both connection.getInputStream() and connection.getOutputStream() in two different ways. You should use one and only one way of reading from and writing to streams, don't mix multiple ways.
When you execute reader.readLine(), the BufferedReader called reader will read up-to 8192 characters from the input stream into its buffer, likely consuming all bytes your client has written. This means that when you construct your DataInputStream around that same input stream and try to read it, there is no data available to read, causing the receiver.read() to block waiting for data. That data is never received as your client has sent all its data, which is now buffered in reader.
In addition, unless your client has closed its output stream, InputStream.readAllBytes() will block indefinitely anyway, because it is only finished when the end-of-stream has been reached. And for socket communication, that only happens when the other side closed its output stream.
Change your code so there is only one way of writing data (though not relevant here), and one way of reading data. In addition, you should establish clearly how you need to read and write data in a protocol, so to avoid consuming too much data at the wrong point, and to know how much data you need to read when.
Of course it does nothing but wait as specified in the javadoc a call to DataInputStream#read() blocks the current thread until data can be read from the input stream.
Your reader = BufferedReader(...) uses the same underlying InputStream which means the all the data the client sent is most likely already consumed by the 'login' logic.
Since neither the client nor the server close their respective streams no EOF is emitted either which leads to the stream 'just dangling' around waiting for more data.
Unless your client sends more data the server will wait eternally.
There are two solutions for your issue.
Either thread you application so that the 'await input' logic is in it's own thread or take a look at javas NIO package (more precisely Channels and Selectors)
I'm trying to implement a server and it does something like this when it receives a message:
try{
ObjectInputStream is = new ObjectInputStream(clientSocket.getInputStream());
String message = (String)is.readObject();
ActivateCommand(message,clientSocket);
is.close();
}
and the ActivateCommand:
private void ActivateEwolfCommand(String msg, Socket clientSocket) throws IOException
{
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
Gson gsonObject = new Gson();
.
//code which makes a Json string
.
os.writeObject(json);
os.close();
}
now, when i tested it with sending a message to the local host with a junit test it worked. But when tried connecting to the server from a C# client, the client connected but the server throw an EOF exception when getting to the point of clientSocket.getInputStream().
I'm guessing it happens because the server did not know when the message is suppose to end but i don't know if thats really the case and if it is, then how can i fix it?
When there is no more data available on the InputStream to read() - that basically is what causes an EOF. How much data is available is determined by the client - the data that it writes to the Socket's OutputStream on its side appears as such on the InputStream of Socket of the server side. You can call InputStream.available() to get an estimate of number of bytes that can be still read().
However your code is trying to read an Object using an ObjectInputStream - this class has its own protocol to read a serialized byte stream and convert that to an object - if it does not find the bytes to complete the task this can throw the EOF exception. If your client is in C# - the format of bytes this writes for a serialized object will definitely not be the same as expected by the ObjectInputStream on the server side.
This is why it's a bad idea to create your own client-server protocol with a socket and object streams. Many people have spent many years bringing you, oh, well:
SOAP
REST
RMI
Hessian
CORBA
Thrift
and the multitude of other protocols out there. Surely one of them, if not 5 or 6, is good enough to solve your problem, including all issues of framing.
If you want to send strings over a socket, then an ObjectInputStream or ObjectOutputStream isn't the right stream implementation. These stream implementations use Java object serialization. Even if you serialize String instances, the resulting bytes are not the same as plain string to byte conversion with the appropriate character encoding.
And a C# application doesn't understand Java serialization at all.
Consider using a PrintWriter to write strings to your stream and a BufferedReader for reading.
PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"));
writer.println(...);
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
String line = reader.readLine();
Then you can read and write strings line by line.
This is only a starting point. If you want to implement your own protocol you have to pay attention to some more points. As an example you can read the specifications for some TCP protocols like POP3, FTP or HTTP 1.0.
I am attempting to send an image from my android device to my computer via a socket. The problem is the input stream on my computer reads in every single byte but the last set of them. I have tried trimming the byte array down and sending it, I've manually written out -1 to the outputstream multiple times but the inputstream never reads -1. It just hangs waiting for data. I've also tried not closing the stream or sockets to see if it was some sort of timing issue, but that didn't work as well.
Client side (Android Phone)
//This has to be an objectoutput stream because I write objects to it first
InputStream is = An image's input stream android
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(object);
objectOutputStream.flush();
byte[] b = new byte[socket.getSendBufferSize()];
int read = 0;
while ((read = is.read(b)) != -1) {
objectOutputStream.write(b, 0, read);
objectOutputStream.flush();
b = new byte[socket.getSendBufferSize()];
}
//Tried manually writing -1 and flushing here
objectOutputStream.close();
is.close();
socket.close();
Server Side (Computer) This bit of code takes place after the object input stream reads in the objects sent. It only starts to read when the file starts to send
File loc = Location of where the file is stored on the computer
loc.createNewFile();
FileOutputStream os = new FileOutputStream(loc);
Socket gSocket = The socket
ObjectInputStream gInputStream = Object Input stream created from the sockets input stream already used to read in the previous objects
byte[] b = new byte[gSocket.getReceiveBufferSize()];
int read = 0;
while ((read = gInputStream.read(b)) != -1) {
os.write(b, 0, read);
os.flush();
b = new byte[gSocket.getReceiveBufferSize()];
}
os.close();
This code never reads in -1 even if I write -1 directly and flush the stream. The outcome is java.net.SocketException: Connection reset when the stream or socket from the android device is closed. The picture is almost completely sent but the very last pixels of the picture are gray. I also even tried using the out/input stream directly from the socket instead of using the already created objectinputstream/objectoutputstream and it still doesn't work.
Firstly, I think you misunderstood the meaning of EOF (-1). It doesn't mean the server wrote a -1, it means the server closed the stream.
I think your main problem though is that both the server and the client are reading in a loop, and neither get to the point where they close the stream. They are deadlocked - both are waiting for the other one to close first.
Your client:
Your server:
If you know that you have no more data to write then just close the stream.
Since you're already using ObjectInputStream and ObjectOutputStream, you can use their respective readObject and writeObject methods to read/write entire objects at a time. Maybe you could send/receive the entire byte array as an object?
On your android:
1) byte[] imageBytes = ...; // contains the Image
2) objectOutputStream.writeObject(imageBytes);
On your computer:
1) byte[] imageBytes = (byte[])readObject();
2) get image from imageBytes
Of course, you'll have to use readObject from within a thread since it'll block.
You are writing byte[] arrays as objects, bur reading bytes. You should be reading Objects and casting them to byte[]. EOS will cause an EOFException to be thrown.
I'd like to write some messages to the server.
Each time, for the tramsmitting only, I'm closing the outputStream and reopen it when I have to send the next message.
os.write(msgBytes);
os.write("\r\n".getBytes());
os.flush();
os.close();
How Can I keep this Socket's OutputStream, os, open and still be able to send the message?
Thanks.
I am missing something here. If you don't call close, it will not close. For example,
os.write(msgBytes);
os.write("\r\n".getBytes());
os.flush();
// Do something
os.write("more message");
os.flush();
// When you are finally done
os.close();
In most protocols, the server accepts som kind of EOF symbol. Send such a symbol instead of closing the stream.
For example, IRC servers interpret "\r\n" as the end of a message. This would be 2 messages on one open OutputStream:
PrintStream printStream = new PrintStream(socket.getOutputStream());
printStream.print("JOIN #channel1\r\n");
printStream.flush( );
printStream.print("JOIN #channel2\r\n");
printStream.flush( );
Also, you should wrap your outputStream with DataOutputStream. This wrapper creates more portable output. Plain OutputStream can cause trouble with certain primitive datatypes if server and client have different computer architectures.
Wrap the Socket's OutputStream in a PrintWriter and call the PrintWriter's println method.
PrintWriter pw = new PrintWriter(socket.getOutputStream());
....
pw.println(message); // call repeatedly to send messages.
....
pw.close(); // when finished writing to server and want to close conn.
I have found the problem and it lays on the client's side.
On the client, I have used -
count = inputStream.read(buffer)) > -1
That means, the client waits till server's outputStream closed, and then processing the incoming data.
I am currently working on a simple proxy server, which receives http request from browser, process it, then forward it to the desire web server.
I try to get the request from the input stream of the socket connected by the browser, everything is fine except that the stream get stuck after receiving the last block of data.
My code is in fact very simple, as shown below:
ServerSocket servSocket = new ServerSocket(8282);
Socket workSocket = servSocket.accept();
InputStream inStream = workSocket.getInputStream();
byte[] buffer = new byte[1024];
int numberRead = 0;
while ((numberRead = inStream.read(buffer, 0, 1024)) != -1){
System.out.println(new String(buffer));
}
The loop simply cannot exit, even the request reception is finished.
Is there any method to workaround this problem?
Thanks in advance for any advice.
As in InputStream javadoc the method will block until the data is available or the EOF is encountered. So, the other side of Socket needs to close it - then the inStream.read() call will return.
Another method is to send the size of message you want to read first, so you know ahead how many bytes you have to read. Or you can use BufferedReader to read from socket in line-wise way. BufferedReader has a method readLine() which returns every time a line is read, which should work for you as HTTP protocol packages are nice divided into lines.
It will cycle until the connection is closed, and the client is probably waiting for HTTP response from you and doesn't close it.
The browser is waiting for a response before it closes the connection.
Your read-method on the other hand will block until the stream/connection is closed or new data is received.
Not a direct solution according to your current code.
As HTTP is a line based protocol, you might want to use a Buffered Reader and call readLine() on it.
The when a http request comes in it will always be concluded with a blank line, for example:
GET /someFile.html HTTP/1.1
Host: www.asdf.com
After sending that request the client connection will then wait for a response from the server before closing the connection. So if you want to parse the request from the user you are probably better off using a BufferedReader and reading full lines until you reach a lines of text that is blank line.