I want to send an InputStream containing XML from the client to a server. Said server manipulates the XML stream using Streaming API for XML (StAX) and sends it back to the client.
I mange to send the XML to the server, the client receives the answer, but doesn't exit because the server never finishes reading the InputStream form the client.
But when the server is just dumping the input to System.out instead of sending something, reading finishes...
edit I forgot to mention that IOUtils.copy() is running in two separate threads on the client.
Here some code to reproduce this, I've replaced the StAX part with IOUtils.copy() on the server.
Server
ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);
Client
Socket socket = new Socket(host, port);
FileInputStream fin = new FileInputStream(file);
OutputStream out = socket.getOutputStream();
IOUtils.copy(fin, out)
InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)
You must flush and close InputStream and OutputStream.
like this:
ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);
//add
out.flush();
in.close();
out.close;
You are probably creating a deadlock.
Client - sends data to the server.
Server - loops data back to the client.
Client - reads data (that the server looped back)
So, while the client is sending data to the server, the server is sending it back to the client.
The client isn't reading that data, it's busy sending.
At some point the TCP buffers fill up, and the server blocks on sending more data to the client. This means the server is blocked on sending data, so eventually the TCP buffers on the receiving side of the server fills up as well, and the client blocks on sending data. Since the client is now blocked on sending, it'll never get to the part where it reads the data that is looped back, so the server will never un-block.
If you're sending a small document, you might not experience this, as all the data fits in the buffers, but once you fill up the buffers, the system will deadlock.
You have to multiplex the sending/receiving. e.g. you could start up a thread on the client that does
InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)
That way receiving can be done in parallel with the client sending data
Or you could use 2 threads on the server side. One for receiving the data, posting data to be sent back to another thread doing the sending (you'll have to build up an internal queue in this case between the threads).
As far as I remember IOUtils.copy() does not flush and does not close the stream. It seems that you do not call neither flush nor close too. Try it. I believe that this is your problem.
Related
I have this piece of server code:
Socket serverSocket = new ServerSocket(8080);
socket = serverSocket.accept();socket = serverSocket.accept();
byte buf[] = new byte[2];
StringBuilder builder = new StringBuilder();
InputStream is = socket.getInputStream();
int r;
while ((r = is.read(buf)) > 0) {
builder.append(new String(buf, 0, r));
}
socket.getOutputStream().write(....
My client only connects to the server, sends bytes through the outputstream and expects some kind of answer from the server.
Socket socket = new Socket("localhost", 8080);
socket.getOutputStream().write("some string".getBytes());
// then manipulating with input stream
The problem is the fact that integer r is never -1, because it becomes -1 only when connection is closed (as I understood). Because of that, my server hangs on "is.read(buf)" expecting client to send something else, while client has finished sending data and already expecting server to send the response.
My question: how does a server know that a client has finished sending its data? What is the appropriate byte buffer size? If I expect large data to be transfered through network, how do I know how many times "is.read(buf)" has to be called? What is the correct server behavior in this case?
UPD: I need them to communicate through the sockets like in chat application. So I cannot close Outputstream of the client socket. Though I tried to close outputstream after writing into it, that led to java.net.SocketException saying that socket is closed.
My server opens a serversocket on a port then waits for clients to connect in an infinite loop. The first client that connects sends some integers and maps then disconnects, however, the server should still wait for other clients. My issue is, that after correctly receiving these from the first client, I can't open any more scanners and printwriters on the same socket's inputstream/outputstream. The client can connect but cannot send nor recieve any data, I just don't understand what's blocking the stream here:
ServerSocket serv = new ServerSocket(port);
while(true) {
Socket sock = serv.accept();
ObjectInputStream instream = new ObjectInputStream(sock.getInputStream());
// receiving and handling the data here
Scanner scan = new Scanner(sock.getInputStream());
// trying to receive lines here from scanner but it's blocked
}
In the client's code I mentioned previously, after sending the maps and other objects, I flush the ObjectOutputStream.
Also, I had a similar problem with scanners before when I closed a scanner on System.in earlier in my code then I couldn't use any scanners on System.in after that, but in this Server code I'm not closing anything after receiving the objects so that's why I don't understand why it's blocked.
So is it possible to re-use the InputStream like this, or should I open another socket for other incoming clients maybe? What should I change if it's not possible?
Supposing I have a servlet that reads and writes a file to a socket and I want to establish a connection between the servlet and the socket, how could this be done?
Well, for a socket, i read somewhere that one just has to do this:
URL url = new URL("http://example.com/getFile");
URLConnection con = url.openConnection();
con.setDoOutput(true);
How could I do the same for a servlet?
I wanted to do this since I will be sending and receiving files between the servlet and the scoket. Also, how would both of them know when the other has sent a file and should read it?
I have searched for this but can't find any site that explains it.
I am unsure what do you mean by 'Socket'. If the socket is a standard protocol (http/https/ftp) then you can use the above piece of code in the Servlet just as you would use in a stand alone program.
If your socket does NOT prescribe to any standard then you might want to open a direct connection using the below piece of code:
Socket socket = new Socket(server,port);
//Get an input stream from the socket
BufferedReader inputStream =
new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//Get an output stream to the socket. Note
// that this stream will autoflush.
PrintWriter outputStream =
new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()),true);
outputStream.println("send_ data");
System.out.println(inputStream.readLine());
socket.close();
Regarding the file sending piece of code, if the primary task involved is file transfer you can use FTP protocol to send files between the servlet and socket.
you can have a file watcher on the socket end to know when a file is transferred. Refer filewatcher and ftp for more information.
You confuse servlets and sockets it looks like. Here is the difference:
Sockets are used for a low-level communication between two points in network. By low-level I mean that you basically send whatever binary data you want over socket and receive some data back. In order to establish a connection there should be a ServerSocket waiting for connections and client socket which establishes connection with server socket.
Servlet is J2EE abstraction. Servets are used in web application containers and those work on top of some protocol (in most cases HTTP). Servlets don't work with sockets, although web server uses sockets internally. Servlets work with Request and Response objects. Your servlet is responsible for processing user request and forming a response.
I need a java program to download a series of file from a web server and I need to be able to close and then reopen the tcp/ip connection between each file download.
Not sure how to do this.
Here is a low-level way of retrieving any information from not only socket 80 (http) but generically to retrieve mail, do a 'telnet' etc:
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
now to do a call to retrieve a page, send the get command, set the content-type, and send two '\n'.
There is a higher-level solution:
Send HTTP GET request with header
You can create a Socket for the IP and port you want to send it to, then read the file into a byte array using a FileInputStream and send that byte array through a DataOutPutStream, then when done just flush the dataOutPutStream and close the Socket and call the function again sending the next file.
use the logic:
Please post something that you have tried.
do{
connection.open;
while(!eof){
fetchfiles();
}
connection.close;
}while(no of files yet to download);
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.