Java OutputStream only flushes data on close - java

Socket socket = new Socket("192.168.178.47", 82);
OutputStream out = socket.getOutputStream();
out.write("{ \"phone\": \"23456789\" }".getBytes());
out.flush();
//Server
InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
int i = 0;
while((i = in.read()) >= 0) {
bOut.write(i);
}
String complete = new String(bOut.toByteArray(), "UTF-8");
I had tried to send data via OutputStream to a socket but the data is not flushing. If I add an out.close(); to the end then it works perfectly, but the socket is closed and I cannot accept the response. Does anybody know why? The server is not giving any type of error. I had used Java 1.7!

It is possible that the server is waiting for the end of line. If this is the case add "\n" to the text

I'm not sure of the labelling "//Server" in your question, but I'm assuming the following code is the server code:
InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
int i = 0;
while((i = in.read()) >= 0) {
bOut.write(i);
}
String complete = new String(bOut.toByteArray(), "UTF-8");
This will continue to read, blocking each time, until it gets a value from read() less than zero. That only happens if the stream is closed.
It really looks like you need to establish your own protocol. So instead of looking for "<=0" look for some constant value that signals the end of the message.
Here's a quick demonstration of what I mean (I didn't have time yesterday). I have 3 classes, Message,MyClient (which also is the main class), and MyServer. Notice there isn't anything about sending or receiving a newline. Nothing is setting tcpNoDelay. But it works fine. Some other notes:
This code only sends and receives a single request and response.
It doesn't support sending multiple Message instances. That would require checking for the start of a Message as well as the end.
Message class:
public class Message {
public static final String MSG_START = "<message>";
public static final String MSG_END = "</message>";
private final String content;
public Message(String string){
content = string;
}
#Override
public String toString(){
return MSG_START + content + MSG_END;
}
}
MyServer class
public class MyServer implements Runnable{
public static final int PORT = 55555;
#Override
public void run(){
try {
ServerSocket serverSocket = new ServerSocket(PORT);
Socket socket = serverSocket.accept();
String message = getMessage(socket);
System.out.println("Server got the message: " + message);
sendResponse(socket);
}catch (IOException e){
throw new IllegalStateException(e);
}
}
private void sendResponse(Socket socket) throws IOException{
Message message = new Message("Ack");
System.out.println("Server now sending a response to the client: " + message);
OutputStream out = socket.getOutputStream();
out.write(message.toString().getBytes("UTF-8"));
}
private String getMessage(Socket socket) throws IOException{
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
StringBuilder sb = new StringBuilder(100);
byte[] bytes = new byte[1024<<8];
while(sb.lastIndexOf(Message.MSG_END) == -1){
int bytesRead = in.read(bytes);
sb.append(new String(bytes,0,bytesRead,"UTF-8"));
}
return sb.toString();
}
}
MyClient class
public class MyClient {
public static void main(String[] args){
MyClient client = new MyClient();
Thread server = new Thread(new MyServer());
server.start();
client.performCall();
}
public void performCall(){
try {
Socket socket = new Socket("127.0.0.1",MyServer.PORT);
sendMessage(socket, "Why hello there!");
System.out.println("Client got a response from the server: " + getResponse(socket));
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public String getResponse(Socket socket) throws IOException{
String response;
StringBuilder sb = new StringBuilder(100);
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
while(sb.lastIndexOf(Message.MSG_END) == -1){
int bytesRead = in.read(bytes);
sb.append(new String(bytes,0,bytesRead,"UTF-8"));
}
response = sb.toString();
return response;
}
public void sendMessage(Socket socket, String message) throws IOException{
Message msg = new Message(message);
System.out.println("Client now sending message to server: " + msg);
OutputStream out = socket.getOutputStream();
out.write(msg.toString().getBytes("UTF-8"));
}
}
The output
Client now sending message to server: Why hello there!
Server got the message: Why hello there!
Server now sending a response to the client: Ack
Client got a response from the server: Ack
Process finished with exit code 0

The problem is not that you are not flushing properly, but that the reading code waits for the socket to disconnect before handling the data:
while((i = in.read()) >= 0)
Will loop as long as something can be read from in (the socket's InputStream). The condition will not fail until the other peer disconnects.

Try using
socket.setTcpNoDelay(true);
There is buffering that occurs for performance reasons (read up on Nagle's algorithm).

Looking at your code it seems ok. However you are sending less than the MTU Nagle's algothrim could be holding it back until enough data is present for a full packet or you close the socket.
So - try this:
socket.setTCPNoDelay(true);
http://en.wikipedia.org/wiki/Nagle%27s_algorithm
https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setTcpNoDelay-boolean-

Related

Java Socket connected but can't sent message by OutputStream.write() but PrintStream will work

I'm an amateur in java socket programming. As I say in title, When I using PrintStream for socket output,it works;but it doesn't work if I using simply OutputStream.
I know the the client connected to the server cause' the server got the info of the client.So I think there must be something wrong with I/O stream, not the socket connection.
btw, I even use the flush() method for OutputStream.I think flush() will force to send all bytes, but it seems like it didn't work.
The Client Code:#line 12:
public class Clinet {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("==========Client============");
Socket socket = new Socket("localhost", 8888);// Server's addr and port
socket.setSoTimeout(3000);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
String msgToSent = "Hello TCP";
outputStream.write(msgToSent.getBytes());
outputStream.flush();// FIXME:why flush() didn't work?why msg wasn't sent.
// read from socket input
String receivedMsg = new String(inputStream.readAllBytes());
System.out.println(receivedMsg);
socket.close();
}
}
When I using a filter stream like PrintStream,the msg can be sent to server.
The Server Code: if using PrintStream it will work perfectly with the Client:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket client = serverSocket.accept();
new Thread(new ServerHandler(client)).start();
}
}
}
class ServerHandler implements Runnable {
private Socket client;
ServerHandler(Socket client) {
this.client = client;
}
#Override
public void run() {
try {
InetAddress clientAddr = client.getInetAddress();
int clientPort = client.getPort();
System.out.println("client connected # " + clientAddr + ":" + clientPort);
InputStream inputStream = client.getInputStream();
OutputStream outputStream = client.getOutputStream();
while (true) {
String msg = new String(inputStream.readAllBytes());// FIXME: Why Server didn't receive Client's msg?
System.out.print("/" + clientAddr + "#" + clientPort + " : ");
System.out.println(msg);
String reply = "I received " + msg.length() + " words.";// return how many words the server got.
outputStream.write(reply.getBytes());
outputStream.flush();// flush to ensure send all msg,but seems doesn't work
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

Writing to a proxy using a socket and returning response to client

I'm trying to create a proxy server in Java that rotates proxies. What I mean is, I am creating a proxy server that passes on the request to another random proxy, gets the response from that random proxy and returns it back to the client.
Something like this:
Client Request -> My proxy server
My proxy server -> random proxy server
random proxy server -> My proxy server
My proxy server -> Client
I have 2 main classes handling this. The first class is called RunnableRequestLayer and it is responsible for reading the client's request, and sending the response back. The second class is RequestMaker which connects to a random proxy, and has a send() and receive() method which send/receive from the random proxy.
Here is the relevant code from both classes:
Class #1: RunnableRequestRelayer
public class RunnableRequestRelayer implements Runnable {
private Socket socket;
private final int maxTries = 5;
public RunnableRequestRelayer(Socket socket) {
this.socket = socket; //This socket is the serverSocket.accept() socket
}
#Override
public void run() {
System.out.println("Got a request!");
try(
PrintWriter out =
new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
){
RequestMaker rm = new RequestMaker();
int tries = 0;
while(tries++ < maxTries){
try{
rm.connect();
} catch(IOException e){
continue;
}
String inputLine;
//This while loop reads the input HttpRequest fine.
while((inputLine = in.readLine()) != null){
if(inputLine.equals(""))
break;
rm.send(inputLine + "\r\n");
//System.out.println(rm.receive());
}
System.out.println("Test"); //This is successfully printing.
String outputLine;
//This output loop is never entered... why?
while((outputLine = rm.receive()) != null){
System.out.println("In output loop");
if(outputLine.equals(""))
break;
out.print(outputLine + "\r\n");
out.flush();
System.out.println(outputLine);
}
rm.disconnect();
tries = maxTries;
}
} catch(IOException e) {
System.out.println("Bad");
}
}
Class #2: RequestMaker
public class RequestMaker {
private Socket socket;
PrintWriter out;
BufferedReader in;
public void connect() throws IOException {
String[] proxy = ProxyGenerator.generate().split(":");
socket = new Socket(proxy[0], Integer.parseInt(proxy[1]));
System.out.println("Connected to proxy - " + proxy[0] + ":" + proxy[1]);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
public void send(String s) {
out.write(s);
out.flush();
}
public String receive() throws IOException {
return in.readLine();
}
public void disconnect() {
try{
out.flush();
out.close();
in.close();
socket.close();
} catch(IOException e) {}
}
}
I tried testing this with fiddler too. I set the proxy to connect to 127.0.0.1:8888 which is Fiddler's proxy server. Once again, the request was received from the client, but the proxy on Fiddler never received it.
My question is: Why is the while loop that reads from the proxy not entering in the first place? I checked if the rm.receive() was returning "" or null using an if, and it wasn't.
Turns out I was not following the HTTP protocol properly. Had to send an empty line after writing the input request to the proxy server.

Java: Implementing a Multithreaded web server

Trying to work on this assignment for practice. Got stuck few with two issues.
Where should I stop the Thread after printing the request on console? Later I would need to do that after sending the response.
From where should I send the response back? I can easily do it from processRequest(). Was thinking if there is anyway to send a HttpResponse back.
Would it be ok to send the response back from HttpRequest class itself?
Code
Main class
public final class WebServer {
public static void main(String[] args) throws Exception {
int port = 1983;
final ServerSocket server = new ServerSocket(port);
System.out.println("Comes here");
Socket client = null;
while (true) {
client = server.accept();
System.out.println("Got the connection" + client.toString());
final HttpRequest request = new HttpRequest(client);
Thread thread = new Thread(request);
thread.start();
}
}
}
HttpRequest.java
final class HttpRequest implements Runnable {
Socket socket;
public HttpRequest(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
processRequest();
} catch (IOException e) {
e.printStackTrace();
}
}
private void processRequest() throws IOException {
String headerline = null;
DataOutputStream out = null;
BufferedReader in = null;
out = new DataOutputStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((headerline = in.readLine()).length() != 0) {
System.out.println(headerline);
}
out.close();
in.close();
socket.close();
}
}
The thread will terminate as soon as the socket is closed.
To output to the client, in this form, you must generate your own Http header that needs to be sent to the client plus all of your data that you're sending to your client. To do this, you can do:
out.writeBytes(<HttpHeaderString>);
Then for your file, you can do something like this:
FileInputStream fileToClient;
OutputStream toClient;
byte[] buffer = new byte[2048];
int bytes = 0;
while ((bytes = fileToClient.read(buffer)) != -1){
toClient.write(buffer, 0, bytes);
}
The page mentions instance of Thread class, but ideally, you don't stop threads, you return them back to the pool. Such that you don't create a new thread for every request but reuse threads.
pool = Executors.newFixedThreadPool(poolSize);
while (true) {
pool.execute(new HttpRequest(client);
}
You can do it from anywhere just keep reference to Socket's OutputStream and don't forget to flush it.
As for the naming, it's bit awkward to send response back from request object. Just rename your HttpRequest to something like HttpRequestHandler, which assumes that you'll handle incoming request here the way you prefer, and it should be fine.

java.net.Socket > InputStream > BufferedReader.read(char[]) blocks thread

I'm trying to use BufferedReader.read(char[]) method instead of the easier, but less versatile BufferedReader.readLine() method for receiving an answer from a Server. BufferedReader is used in parallel with BufferedOutputStream and, in the code below, the read(char[]) method blocks everything, the last console output is "new buffer, waiting to read."
Client:
public class MessageSender extends Thread {
private String message;
MessageSender(String message) {
this.message = message;
}
public void run() {
try {
Socket sk = new Socket("192.168.1.4", 3000);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write(message.getBytes());
bo.flush();
char[] c = new char[100];
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
StringBuffer sb = new StringBuffer();
System.out.println("new buffer, waiting to read.");
int ix = 0;
while (ix != -1) {
ix = br.read(c);
sb.append(new String(c));
}
String message = sb.toString();
System.out.println("reply: " + message);
sk.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Server:
public class MessageReceiver extends Thread {
public void run() {
try {
ServerSocket ss = new ServerSocket(3000);
System.out.println("server socket open");
while (true) {
Socket sk = ss.accept();
System.out.println("new connection");
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
String line = br.readLine();
System.out.println("received line: " + line);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write("ack".getBytes()); bo.flush(); //bo.close();
sk.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Main:
public class Main {
public static void main(String[] args) {
MessageReceiver mr = new MessageReceiver();
mr.start();
while (true) {
String msg = new Scanner(System.in).nextLine();
MessageSender ms = new MessageSender(msg+"");
ms.start();
}
}
}
Everything works fine as long as the BufferedReader.read is not called. But as the code is right now, the output doesn't seem to get sent to the server.
UPDATE
As answered by #JB Nizet, the problem lies in the server script that uses readLine() and waits for either EOL character or the connection end. Therefore, adding "\n" to the message sent from the client side solved the deadlock:
bo.write((message+"\n").getBytes());
When the server accepts a connection from the client, the first thing it does is:
String line = br.readLine();
So, it blocks until the client sends a complete line of text. The server only knows the line is complete if it reads an EOL character, or if the stream is closed by the client.
When the client starts, the first thing it does is
bo.write(message.getBytes());
And message is a line of text, without any EOL. Then the client does
ix = br.read(c);
so it waits for a response from the server, which is itself waiting for an EOL from the client.
You have implemented a networked deadlock.

Socket data does not appear to be getting through to client

I've written some serverside socket handling code and I'm concerned that potentially my packets are not always making it back to the client. I am logging all my events and in my log files it says I am sending the information. But the client is also logging events and in their logs they say they do not receive anything.
My code to send the data is as follows:
public void write(Packet packet) {
String data = packet.serialize();
log("Send=[" + data + "]", "Write"); // log to file
try {
_writer.write(data);
_writer.flush();
} catch (Exception ex) {
log(ex, "write");
}
}
Each socket is created on a new thread and I create my writers and readers immediately like so (in the public run method):
// _sockt is a Java Socket object
_writer = new BufferedWriter(new OutputStreamWriter(_socket
.getOutputStream()));
_reader = new SocketReader(_socket);
SocketReader is just a wrapper class I created for listening for responses and has a public read method like so:
public String read() throws IOException, SocketTimeoutException {
_socket.setSoTimeout(_timeOut);
if(_reader == null)
_reader = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
// read from the stream
return new PacketDataInputStream(_reader).read();
}
The PacketDataInputStream wrapper class:
BufferedReader _reader = null;
public PacketDataInputStream(BufferedReader reader)
{
_reader = reader;
}
public String read() throws IOException, SocketException {
StringBuilder builder = new StringBuilder();
int c = 0;
while((c = _reader.read()) != -1)
{
char ch = (char)c;
builder.append(ch);
if(ch == PacketConstants.ETX)
break;
}
if(builder.length() > 0)
return builder.toString();
else
return null;
}
The way I'm creating the actual socket listener objects is pretty standard I think:
InetAddress address = InetAddress.getByName(IP);
server = new ServerSocket( port, 0, address);
// My own manager class to handle all the sockets connected
WebSocketManager manager = new WebSocketManager(this);
Socket connection = null;
while(bContinue)
{
connection = server.accept();
if(bContinue) {
// assign the socket to a new thread and start
// that thread
manager.newSocket(connection);
} else {
connection.close();
}
}
Is is possible that I'm using the wrong objects for sending the data back.
Should I even be using a bufferedwriter and reader? I had thought that these were the best way to go but now I'm not so sure.
It's important to note that this does not happen all the time, just sporadically. It could be the clients code having bugs but I need to make sure that I'm doing it correctly before going back to them.
This code is run on a Linux Ubuntu server. Logging occurs to a text file, nothing special there. My log files show the Send="" data going back to the client and no exception so it appears as if the .write and .flush() worked? Socket connections are persistant and only closed by the client and or network issues.
UPDATE ----- Client Side code -------:
I did manage to get some of the client side code for how they are handling the send and receiving of data (just in case it's more obvious on their end). The client is actually connecting to this server via an Android device (if that helps).
Creation of socket
static final int BUFFER_SIZE = 20000; // Maximum packet size
java.net.InetAddress server = java.net.InetAddress.getByName(url);
socket = new Socket(server, port);
// Set socket options:
socket.setReceiveBufferSize(BUFFER_SIZE);
socket.setSendBufferSize(BUFFER_SIZE);
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
Sending:
try {
// Send the packet:
OutputStream stream = socket.getOutputStream();
stream.write(p.getByteArray ());
stream.flush();
// Update the time:
lastPacketSendTime = new Date ();
} catch (IOException e) {
setError("Error sending packet (" + e.getMessage() + ")", ERROR_IO);
return false;
}
Receiving:
socket.setSoTimeout(timeout);
// Get the reader:
inputStream = socket.getInputStream();
while (true) {
// Get the next character:
int value = inputStream.read();
// Check for -1, indicating that the socket is closed:
if (value == -1) {
// The socket is closed remotely, so close it locally as well:
disconnect();
inputStream = null;
return null;
}
// ... and a bunch of other stuff to handle the actual data
}
EDIT 14-Nov:
This is actually proving to be more of a problem now. Both the client logs and the server logs appear to be sending. But at times the data doesn't appear to come through or if it does it is sometimes coming through 10 - 30 - 60 second delayed.
I can provide more information if required.
When you use BufferedReaders and BufferedWriters things get buffered. How about using the input and output streams directly.. Also, writers are character based, I don't know if you need to send binary data but if so that will be a problem with writers.
I am not sure whether this will be to your any use or not.. but i am giving you the code i used for client server communication..
Client Side:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket("127.0.0.1", 4444);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server Code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}

Categories

Resources