Replacement of Inputstream in java which doesn't have blocking function - java

When I try to call .read method of inputstream with multiple parallel request,time response increases. I think it is blocked till it read previous one response.
What will be the alternative for InputStream ?
i m using UNIX domain socket and from there i m trying to read data from inputstream,Here the code i m using----------
-
UnixDomainSocketClient socket = new UnixDomainSocketClient(sockFileName, JUDS.SOCK_STREAM);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
out.write(inputStreamData.getBytes());
String modelResponse = "";
while (true) {
try {
modelResponse += (char) in.read();
} catch (Exception e) {
break;
}
}
out.flush();
socket.close();
in.close();
out.close();
}

When I try to call .read method of inputstream with multiple parallel request,time response increases. I think it is blocked till it read previous one response.
No. It is blocked until data arrives on this socket. It has nothing to do with the other sockets, except for the overall load on the machine. Reads are not sequentialized as between different input streams.
What will be the alternative for InputStream?
Non-blocking I/O or asynchronous I/O via the NIO package, but you haven't correctly identified your problem. You may have some undue synchronization in your application. Or maybe your diagnosis is incorrect.

Related

How to display content that has been written to a Socket.OutputStream while maintaining a persistent connection?

Suppose that I have a multi-threaded web server that only allow clients to perform GET requests for a couple of HTML files. I want to maintain a persistent connection (i.e HTTP Connection: keep-alive) while "dynamically" displaying the content for each request the client makes. Like if they first request index.html then foo.html etc. The problem right now is when I don't close the streams and socket, the program will hang until it happens.
Simply put, the multi-threaded web server consist of a thread pool (Java's ExecutorService) with a ServerSocket that listens to a specific port (e.g 9000) and selects a thread from the threadpool to handle the opening of a client socket to the server. It is basically the same setup as showed in http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html.
My modified setup looks like this:
WorkerRunnable.java:
public void run() {
try {
InputStream input = this.clientSocket.getInputStream();
OutputStream output = this.clientSocket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
List<String> headers = readInputStream(input)
Request request = new Request(headers);
Response response = new Response(request);
// response.raw() returns correctly formatted HTTP
output.write(response.raw().getBytes(StandardCharsets.UTF_8));
// close the socket if the client specifies Connection: close
if (!request.keepAlive()) {
output.close();
input.close();
} else {
this.clientSocket.setKeepAlive(true);
}
} catch (IOException e) {
e.printStackTrace();
}
private List<String> readInputStream(InputStream input) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
List<String> headers = new ArrayList<>();
while ((line = reader.readLine()) != null && !line.isEmpty()) {
headers.add(line);
}
return headers;
}
My problem is that the HTML only will be displayed when the input/output stream (and thus also the socket) are closed. As far as I understand, the Socket.InputStream will basically hang until it receives an EOF token - which it receives when the stream closes. But if I want to maintain a persistent connection, it doesn't really make sense to close the streams and client socket. So I was wondering how to maintain a persistent connection while also displaying the content of multiple GET requests from clients (assuming this is the correct approach)? If not, please let me know if I've approached this task wrongly.
I have tried to flush the output stream as suggested here, but the problem still persists.

Non-blocking IO solution in Java

I'm writing a program that uses multiple SSL connections. Basically, my code has to 3 separate programs that can connect to one another and communicate through SSL sockets.
The problem I'm having is with blocking I/O. For example, my class CLAFrame.java has to be able to detect and handle input from a stream, but also be able to carry out other functions. I don't want this to block the entire program and freeze it up waiting for input (like it is now).
Here's how I had it set up.
static void initializeCLAConnection(){
try {
SSLServerSocketFactory sslserversocketfactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket =
(SSLServerSocket) sslserversocketfactory.createServerSocket(3577);
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
OutputStream outputstream = sslsocket.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
input=bufferedreader;
output=bufferedwriter;
System.out.println("Connection accepted from: "+sslserversocket.getInetAddress());
String string=null;
//RECEIVING INPUT
while(input.ready()){
System.out.println("CLA receiving msg");
// while ((string = input.readLine()) != null) {
string=input.readLine();
System.out.println(string);
/*
* HEADERS FOR INPUT RECEIVED
* Format: VAL Ryan Smith
* VAL - requesting validation id
*/
String header=null;
String rest=null;
header=string.substring(0, 3);
if(string.length()>3){
rest=string.substring(4, string.length()-1);
}
//perform actions based on input
switch(header){
case "VAL ":
//do something
requestValidationID(rest);
break;
default:
break;
}
}
}
// System.out.println("Successfully established CLA server on SSL port 3577");
catch (Exception exception) {
exception.printStackTrace();
}
}
Note - Previously, I had my while loop setup as
while ((string = input.readLine()) != null) {
However, clearly this will block I/O until input is received. I then switched to
while(input.ready()){
This has stopped the blocking but now my buffer (input) is not receiving anything at all when I write to the stream.
Is there a better way to do this? This program is set up as a GUI so I need the buffer to be able to receive input, but I also need to be able to simultaneously use other buttons and functions on the program without it blocking everything.
Should I make it multithreaded? A thread for reading the buffer and another for all other functions? I'm a bit confused what to try next.
Any input/advice would be greatly appreciated, thanks!
You're trying to re-invent the wheel here. There are many non-blocking frameworks out there, all built on top of Java NIO (which provides non-blocking IO functionality in Java).
Netty is one such example, very fast and not the highest abstraction.
Edit:
Considering this is a school project, and that you just need to be able to do things simultaneously, I'd say what you want isn't non-blocking code, you just want your blocking code to run in a separate thread.
See Java's Executors for that.

Java Networking: Explain InputStream and OutputStream in Socket

I have created a server by using ServerSocket. After that, I have created Client using Socket, and connect to this server.
After that, I do "some stuff" with InputStream and OutputStream is taken from Socket Object. But, I don't really understand inputStream and outputStream so much. Here is my simple code :
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
The result will be : "Hello World" and "Hello StackOverFlow".
Here is server side code :
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
My question is :
When I use sockOutput.write and I can get back those message back by sockInput.read. So, those message has been saved, right? If this true, does it saved on Server I have created or just saved in some other thing such as Socket Object.
If I have written to socket String A1, A2,... An so I will receive A1, A2, ... An String respectively, right?
A socket is an abstraction that you use to talk to something across the network. See diagram below...
In Java, to send data via the socket, you get an OutputStream (1) from it, and write to the OutputStream (you output some data).
To read data from the socket, you get its InputStream, and read input from this second stream.
You can think of the streams as a pair of one-way pipes connected to a socket on the wall. What happens on the other side of the wall is not your problem!
In your case, the server has another socket (the other end of the connection) and another pair of streams. It uses its InputStream (2) to read from the network, and its OutputStream (3) to write the same data back across the network to your client, which reads it again via its InputStream (4) completing the round trip.
Client Server
1. OutputStream -->\ /--> 2. InputStream -->
Socket <--> network <--> ServerSocket |
4. InputStream <--/ \<--3. OutputStream <--
Updated: in reply to comment:
Note that the streams and sockets just send raw bytes; they have no notion of a "message" at this level of abstraction. So if you send X bytes and another X bytes, then read X bytes and read another X bytes, then your system behaves as if there are two messages, because that's how you've divided up the bytes.
If you send X bytes, and another X bytes, then read a reply of length 2X, then you might be able to read a single combined "message", but as you've noticed, the underlying implementation of the streams can choose when to deliver chunks of bytes, so it might return X bytes, then X bytes, later, or 2X at once, or 0.5X four times...
InputStream and OutputStream are two completely separate streams. What you write into one has no a priori relation to what you read from the other. The InputStream gives you whatever data the server decides to send to you. I would also like to comment on this piece of your code:
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
You use the length of a string test (not shown in your code), which has nothing to do with the byte array you are passing as the first argument. This can cause an ArrayIndexOutOfBoundsException or truncation of your intended message.
Additional comments to your updated question
Reviewing your server-side code, it is not quite correctly written. You need to have try { handleConnection(...); } finally { socket.close(); } to ensure proper cleanup after an error, as well as when completing normally. Your code never closes anything on the server side.
Finally, and most critically, your entire code is written in a way that can result in a deadlock. Normally you need a separate thread to read and to write; otherwise the following may happen:
You attempt to write some data to the output;
The server reads it and tries to respond with data in your input;
But, since the buffers are too small, you don't manage to send everything because the server wants to first send something to you, then receive the rest; but you don't get to the receiving part before you have sent everything you've got.

Java - Fastest Stream for TCP/HTTP Communication?

I'm trying to write a Java HTTP Proxy Tunnelling program, and I need an experts advice about the best and fastest stream to use for the communication.
I've implemented the basic functionality and everything works fine. The only matter is communication speed or performance. My HTTP proxy system consists of a server program, running on a remote server and a client program running on the local machine. So far, the program looks like this:
Listener.java :
/**
* Listens and accepts connection requests from the browser
*/
ServerSocket listener = null;
try {
listener = new ServerSocket(port, 128);
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
ExecutorService executor = Executors.newCachedThreadPool();
Socket connection;
while (!shutdown) {
try {
connection = listener.accept();
executor.execute(new ProxyTunnel(connection));
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
ProxyTunnel.java :
try {
byte[] buffer = new byte[8192]; // 8-KB buffer
InputStream browserInput = browser.getInputStream();
OutputStream browserOutput = browser.getOutputStream();
// Reading browser request ...
StringBuilder request = new StringBuilder(2048);
do {
int read = browserInput.read(buffer);
logger.log(read + " bytes read from browser.");
if (read > 0) {
request.append(new String(buffer, 0, read));
}
} while (browserInput.available() > 0 && read > 0);
// Connecting to proxy server ...
Socket server = new Socket(SERVER_IP, SERVER_PORT);
server.setSoTimeout(5000); // Setting 5 sec read timeout
OutputStream serverOutput = server.getOutputStream();
InputStream serverInput = server.getInputStream();
// Sending request to server ...
serverOutput.write(request.toString().getBytes());
serverOutput.flush();
// Waiting for server response ...
StringBuilder response = new StringBuilder(16384);
do {
try {
read = serverInput.read(buffer);
} catch (SocketTimeoutException ex) {
break; // Timeout!
}
if (read > 0) {
// Send response to browser.");
response.append(new String(buffer, 0, read));
browserOutput.write(buffer, 0, read);
browserOutput.flush();
}
} while (read > 0);
// Closing connections ...
server.close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
} finally {
try {
browser.close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
The server program uses a similar fashion and sends the HTTP request to the destination server (e.g. www.stackoverflow.com) and forwards the response to the client program, where the client program forwards the response to the local browser.
How can I improve the performance of these TCP/HTTP communications?
Does using buffered streams such as BufferedInputSream and BufferedOutputStream improve communication performance?
Will I gain any performance improvements if I use java.nio Channels and Buffers, instead of java.net Sockets and java.io Stream?
Don't do it yourself
Advice 0: there are plenty of proxy servers out there, much more scalable, stable and mature. Do you really need to write your own?
Don't use StringBuilder/String to buffer request
byte[] buffer = new byte[8192]; // 8-KB buffer
//...
browserInput.read(buffer);
//...
request.append(new String(buffer, 0, read));
//...
serverOutput.write(request.toString().getBytes());
This is flawed for several reasons:
you are assuming your HTTP calls are text (ASCII) only, binary data will be malformed after transforming to String and back to byte[], see: String, byte[] and compression
even if the protocol is text-based, you are using system's default encoding. I bet this is not what you want
finally, the most important part: do not buffer the whole request. Read chunk of data from incoming request and forward it immediately to target server in one iteration. There is absolutely no need for the extra memory overhead and latency. Immediately after receiving few bytes dispatch them and forget about them.
Don't use Executors.newCachedThreadPool()
This pool can grow inifinitely, creating thousands of threads during peak. Essentially you create one thread per connection (except that the pool reuses free threads, but creates new if none available). Consider Executors.newFixedThreadPool(100) - 100-200 threads should be enough in most cases. Above that you'll most likely burn your CPU barely in context switching, without doing much work. Don't be afraid of latency, scale out.
Use non-blocking netty stack
Which brings us to the final advice. Drop blocking sockets altogether. They are handy, but don't scale well due to thread-per-connection requirement. Too much memory is spent to hold stack, too much CPU is wasted for context switching. netty is great and it builds powerful abstraction over NIO.
Check out the examples, they include HTTP client/server code. There is a bit of a learning curve, but you can expect performance growth by several order of magnitued.

Java client socket using writeBytes

I'm reading a string from a buffer and writing it to a server. The problem I'm having is that the string never gets received by the server when I leave the socket open and write in a loop.
When I use this:
try {
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
String message = null;
while ((message = buffer.get()) != null){
out.writeBytes(message);
}
out.close();
send.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
the server doesn't receive the string, but when I do this it works properly:
try {
String message = null;
while ((message = buffer.get()) != null){
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
out.writeBytes(message);
out.close();
send.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Obviously I don't want to keep opening and closing the socket, though. What is the problem?
You need to flush your socket every time you want to send a data packet.
Closing a socket forces an automatic flush and that explains why your data is getting sent on socket close.
The data is not being written to the socket even when you close it? (in your first snippet that is)
Also, have you tried to use the flush method? You can read about it here: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/DataOutputStream.html#flush() and your code will look like:
try {
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
String message = null;
while ((message = buffer.get()) != null){
out.writeBytes(message);
out.flush();
}
out.close();
send.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Let me make a guess.
Does the buffer.get() method block? If so, then the problem is that out.writeBytes(message) does not guarantee that the entire byte representation to be pushed to the server. Instead. there is a good chance that your client has buffered bytes waiting to be flushed through to the server.
If this is what is going on, then calling flush after each call to writeBytes will fix the problem.
But if the buffer.get() method doesn't block, then calling flush won't make any difference. In fact, it will just increase the network traffic. So adding the flush "just in case" is a bad idea.
Another possibility is that there is something wrong with the server-side code.

Categories