I'm writing a simple server in Java, and I'm able to retrieve incoming data from the client on the server side, but not on the client side due to a 2000ms timeout. Anyone know why this times out?
This is the server's code:
private static void listen() throws IOException {
while(true) {
Socket clientSocket = serverSocket.accept();
StringBuilder bufferedStringInput = new StringBuilder();
CharBuffer cbuf = CharBuffer.allocate(4096);
try {
InputStream is = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF8"));
int noCharsLeft = 0;
while ((noCharsLeft = br.read(cbuf)) != -1) {
char[] arr = new char[noCharsLeft];
cbuf.rewind();
cbuf.get(arr);
bufferedStringInput.append(arr);
cbuf.clear();
}
System.out.println(bufferedStringInput.toString());
} catch (IOException e) {
System.out.println("Error received client data: " + e.getMessage());
}
String message = "Hello client";
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream());
out.print(message);
} catch (IOException e) {
System.out.println("Error getting output stream from client: " + e.getMessage());
}
clientSocket.close();
}
}
You're reading the input until end of stream, which only happens when the peer closes the connection, then you're trying to write to it, so of course you get a broken pipe. Doesn't make sense. You should just read the input until you have one entire request, whatever that means in your protocol.
There are other problems lurking here:
If the client code uses readLine(), you're not sending a line terminator: use println(), not print(), and close the PrintWriter, not just the client socket.
cbuf.rewind()/get()/clear() should be cbuf.flip()/get()/compact().
But it would make more sense to read directly into a char[] cbuf = new char[8192]; array, then bufferedStringInput.append(cbuf, 0, noCharsLeft), and forget about the CharBuffer altogether. Too much data copying at present.
noCharsLeft is a poor name for that variable. It is a read count.
Related
Having read tens of examples online, I am still stuck with the problem.
I am sending a message from my client in Java to a server in C++. After receiving the hand-shake message, the server sends back the following data:
"0000:1111:2222:3333:4444
END_CONNECT_DATA"
As soon as the last line (terminator) is read by the client, it should close the connection.
This is how I do it:
Socket socket = null;
String terminator = "END_CONNECT_DATA";
try
{
int serverPort = 7767;
String ip = "192.168.1.10";
String messageOut = "HAND-SHAKE MESSAGE";
socket = new Socket(ip, serverPort);
DataInputStream input = new DataInputStream( socket.getInputStream());
DataOutputStream output = new DataOutputStream( socket.getOutputStream());
//Send message
output.writeBytes(messageOut);
//Read Response
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuffer sb = new StringBuffer();
String s = "";
while((s = br.readLine()) != null)
{
System.out.println("CHECK !!!");
System.out.println(s);
sb.append(s);
if(s.contains(terminator))
{
System.out.println("CHECK TERMINATOR");
break;
}
}
socket.close();
String data = sb.toString();
System.out.println("FULL DATA:\n");
System.out.println(data);
}
catch (UnknownHostException e)
{
System.out.println("Sock:"+e.getMessage());
}
catch (EOFException e)
{
System.out.println("EOF:"+e.getMessage());
}
catch (IOException e)
{
System.out.println("IO:"+e.getMessage());
}
finally
{
if(socket!=null)
{
try
{
socket.close();
}
catch (IOException e)
{
}
}
}
}
What I get back from the server is only the first line. The cursor goes to the next line and continues blinking. The socket connection is not closed. Looks like the client is not reading the terminator (the second line of the message) at all.
Any ideas?
Thanks a lot!
As documented, the loop fails to read in the second line as it's not terminated with \r or \n. Therefore, returning only the result up till then, which is the first line as described.
You'll need to either add in a \r or \n right after the terminator or use BufferedReader.read() instead and check manually or adopt another strategy to read in the message
Clearly the peer is neither sending a line terminator after the last line nor closing the socket. Ergo using readLine() to read those messages is not correct. If you can adjust the peer, do so.
I have server:
StringBuilder sb = new StringBuilder();
try {
ServerSocket ses = new ServerSocket(7841);
Socket s=ses.accept();
Reader br = new InputStreamReader(s.getInputStream());
OutputStream os = s.getOutputStream();
os.write("string from system".getBytes());
os.flush();
char[] request = new char[6];
int count = br.read(request);
while (count!=-1) {
sb.append(new String(request, 0, count));
count = br.read(request);
System.out.println(count);
System.out.println(sb);
}
System.out.println("111"+count);
System.out.println(sb);
}
catch (IOException e) {e.printStackTrace();}
System.out.println(sb);
and client :
StringBuilder sb = new StringBuilder();
try {
Socket s = new Socket("127.0.0.1",7839);
Reader br = new InputStreamReader(s.getInputStream());
OutputStream os = s.getOutputStream();
os.write("string from project".getBytes());
os.flush();
char[] request = new char[6];
int count = br.read(request);
while (count!=-1) {
sb.append(new String(request, 0 , count));
// if (sb.toString().endsWith("</family>")) {
// break;
// }
count = br.read(request);
System.out.println(count);
System.out.println(sb);
}
System.out.println("111"+count);
System.out.println(sb);
}
catch (IOException e) {e.printStackTrace();}
System.out.println(sb);
The problem is I can not read the string till the end. For example, the server read only "string from projec".
Also the code System.out.println("111"+count); is not reached neither in client nor in server. What is wrong with the program? Thank you very much for any ideas.
Your program is fine, the only problem is your Server listening on port 7841, but your client try to connect on the port 7839, they must connect to the same port.
I think you need to figure out the protocol things like:
Server starts to listen, there is no client yet, the server is waiting on method accept();
When your client get connected, you must decide: who will first talk, who will response, what sign is beginning of the conversation and what sign is the end of the conversation, after this both the client and server can close this connection properly. Refer to this link https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
If you don't like the request-response mode, you can read and write simultaneously, then maybe the thread approach is better, use two threads to separate reading and writing process, so the read process will not block the write process.
Back to your question, the read process blocks program in while loop, so the line System.out.print(...) can not be reached.
I am trying to create an application that will count the amount of times a button has been clicked. This client would connect to a server, and when the user clicks the button, it should increment the counter on the server. The server should then send back the current amount of clicks to the client. But that's where I'm having a bit of problems.
This is the relevant client-sided code.
public void actionPerformed(ActionEvent arg0) {
try {
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String target = "";
bw.write("increment" + "\n");
bw.flush();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String id = br.readLine();
System.out.println("test: " + id);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
The client stops at:
String id = br.readLine();
I just want to get the output from the server.
This is the relevant server-sided code.
public void run() {
try {
while (true) {
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is); //Create the input Streams
BufferedReader br = new BufferedReader(isr);
String input = br.readLine();
System.out.println("got input");
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
System.out.println("wrote to out");
if(input.equals("increment" + "\n")) {
totalBets++;
System.out.println("inif");
bw.write(totalBets);
System.out.println("wrote");
bw.flush();
System.out.println("flushed");
System.out.println("Total Bets: " + totalBets);
}
}
} catch (IOException e) {
log("Error handling client# " + clientNumber + ": " + e);
} finally {
try {
socket.close();
} catch (IOException e) {
log("Couldn't close a socket, what's going on?");
}
log("Connection with client# " + clientNumber + " closed");
}
}
I found that it also stops here:
String input = br.readLine();
I'm just trying to get the bw.write("imcrement") from the client, so the server can increment the counter, and send back the total clicks.
Any help?
Thank you.
You are writing the totalBets value using BufferedWriter.write(int).
This interprets the value as a single character. So, for example, if totalBets is 65, it writes the character 'A'!
Moreover, it does not add a newline. So the client reads that 'A' but tries to read more characters as it is trying to read a whole line. Remember that you have to write lines to read lines.
Thus, you should replace the part that writes totalBets with:
bw.write(String.valueOf(totalBets));
bw.newLine();
Also remember, as I pointed in a comment, that you have to write a line with a \n (or preferably BufferedWriter.newLine()), but when you read the line on the other side, the line separator is stripped away, so you should compare the string you expect without a \n.
You need to set TCP_NODELAY on the client's socket. The default is for data to be buffered until it will fill an entire packet. When the buffer is full, a packet is sent. However, for this protocol you want the data to be sent immediately so that the server can respond.
I frequently use wireshark when testing and debugging my networking code. It will show exactly what packets are sent and received. (note, however, that on Windows you can not capture from the loopback interface; this is a limitation of Windows and does not apply to other systems)
I have the following problem, I have a simple TCP class in my application that sends a message off to a device for a query, the device then responds with the message however there is no end of line character of any description because it is coming from a serial converter, after initially atempting to use the readline function and discovering it requires the eol character before outputting I have tried the scanner function which works fine unless the device doesnt reply to that request for some reason, my application then freezes, is it possible to set a timeout on the scanner function so that it then drops the connection and moves on or is there a better way to do this? my code is below:
public String Send_TCP ( InetAddress IPAddress, int POrt, String InData) throws IOException
{
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
socket = new Socket(IPAddress, POrt);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
System.exit(1);
}
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
;
System.out.print("Connected, Sending:"+ InData);
out.println(InData);
System.out.println("Equals");
String str1 = new Scanner(in).useDelimiter(">").next() + ">";
System.out.println(str1);
System.out.println("Equals");
out.close();
in.close();
read.close();
socket.close();
return str1;
}
}
I'm not sure that I understand your question correctly but you can set a timeout on the socket: socket.setSoTimeout(int timeout).
See: javadoc
I believe the following achieves what I need it to, basically checking if the buffer exists, if it doesnt then it waits and checks again avoiding the trap of the scanner function if the message never arrives if it does it reads it.
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(sock.getInputStream()));
int count = 1;
do {
if (rd.ready()){
System.out.println ("Response Ready");
str = new Scanner(rd).useDelimiter(">").next()+">";
count = 501;
}
Thread.sleep(10);
System.out.println ("Response Not Ready" + count);
count ++;
} while (count < 25);
yes i did look at the tutorials on sun and they didn`t help in my case, only transferred the first command.
I`ve got a method
public void openConnection() throws IOException{
serverSocket = new ServerSocket(5346);
Socket simSocket = serverSocket.accept();
is = simSocket.getInputStream();
os = simSocket.getOutputStream();
writer = new PrintWriter(os);
isReader = new InputStreamReader(is);
reader = new BufferedReader(isReader);
System.out.println("Connection succesfull.");
}
and
public void sendTo(int command) {
try {
writer.println(command);
writer.flush();
} catch(Exception e) {
System.out.println("Error sending command to the robot");
System.out.println(e.toString());
}
}
in the sending side, and
public static void setUpConnection() {
try {
socket = new Socket(InetAddress.getLocalHost(), 5346);
is = new InputStreamReader(
socket.getInputStream());
reader = new BufferedReader(is);
writer = new PrintWriter(socket.getOutputStream());
System.out.println("Simulator: connection succesful");
} catch (IOException e) {
e.printStackTrace();
}
}
and
while (true) {
intCommand = reader.read();
ett = reader.readLine(); // does nothing, but without this line it doesn't work
command = (char) intCommand;
in the receiving side. It works perfectly sending a char or an ascii number of a char. What i need is to change this code to send integers or simply array of bytes instead of a char. if i simply leave just InputStream and OutputStream it does receive the first command and thats it, while these methods continuously receives what is sent through sendTo. Even in sockets documentation they only have exmample with sending chars only.
Just code your server to store the received value as an int instead of a char.