I am having a field day trying to figure out why my Java code is not working.
I am supposed to receive the following messages from a C program via sockets.
1~message~i love you\r\n
2~message~do you love me?\r\n
3~message~when are we going to meet again?\r\n
4~message~How about now?\r\n
5~message~Oh! I'm pregnant!\r\n
Instead, I am receiving the following messages instead.
1~message~i love you\r\n
2~message~do you love me?\r\n
2~message~do you love me?\r\n
5~message~Oh! I'm pregnant!\r\n
I ran a port redirector on my laptop and found out that the C program is transmitting the messages correctly. It's my Java program that is not receiving them properly.
I am using Java NIO Channels to receive the messages.
My code as follows:
StringBuffer stringBuffer = new StringBuffer();
int pos = 0; // position of Buffer
// initialize server and client sockets
ServerSocketChannel serverChannel = null;
SocketChannel clientChannel = null;
// initialize ByteBuffer
ByteBuffer inBuffer = ByteBuffer.allocateDirect(65536);
inBuffer.order(ByteOrder.LITTLE_ENDIAN);
try {
serverChannel = ServerSocketChannel.open();
SocketAddress port = new InetSocketAddress(8080);
serverChannel.socket().bind(port);
while (true) {
clientChannel = serverChannel.accept();
while ((bytesRead = clientChannel.read(inBuffer)) != -1) {
inBuffer.flip();
while (inBuffer.get(pos) != '\r') {
stringBuffer.append((char) inBuffer.get(pos));
pos++;
} // end while loop checking for bytesRead
//increment over \r and \n
inBuffer.get();
bytesRead--;
inBuffer.get();
bytesRead--;
pos = pos + 2;
System.out.println(stringBuffer);
stringBuffer.setLength(0);
pos = 0;
} // close while reading bytesRead loop
} // close while(true) loop
} catch (IOException ex) {
}
I suggest you try plain IO which is simpler for this use case.
ServerSocket serverSocket = new ServerSocket(8080);
while(!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
System.out.println("Accepted socket "+socket);
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
StringBuilder sb = new StringBuilder();
int b;
while((b = bis.read())>=0) {
if (b == '\r')
b = bis.read();
if (b == '\n') {
System.out.println(sb);
sb.setLength(0);
} else {
sb.append((char) b);
}
}
System.out.println("Closing socket.");
socket.close();
}
Do you have to use NIO for this? It's generally a lot harder to get right (at least for me). My guess is that the problem is that you're always reading, but you're calling flip exactly once per read... whereas I'd expect to see two flips, or possibly a flip before the read and then a clear at the end of the processing.
Note that you're also completely ignoring bytesRead - why bother decrementing a variable which you're then reassigning without reading?
Furthermore, you're assuming you get exactly one \r from each read call. What if you receive two lines in one call, or one imcomplete line?
I'm not qualified to give the correct NIO code, but I'd recommend that you try to get it working with a plain InputStream first and then move onto NIO.
SocketChannel.read puts data into the buffer at the buffers current position. You're iterating the buffer from position 0 every time.
If you get two lines in one read you're only handling up to the first \r and then continuing by reading again. You may miss the final lines this way.
Related
I have developed a small java client that suppose to communicate with a tool installed on unix-server.
I'm working with Socket first time so could do something wrong. I am also limited to Java 6.
In brief code looks like this
I use Socket to establish connection.
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(endpoint, port);
socket.connect(socketAddress, 5000);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Here is how I send message
out.println("Hello");
out.flush();
And here is how I read response
String res = "";
int letter;
while(letter = in.read() != -1) {
char c = (char) letter;
res += c;
}
F.x. If I send a message "Hello", I will receive answers with 2 lines (see example below)
> Hi there
> My name is Robot
The things stuck when I read next character after "Robot\n", I expected that in.read() != -1 will be true and thus it will stop itself, but that is not a case and instead everything just stuck.
What could be the reason to this and how to solve? Thanks.
Please let me know if I need to provide more information.
I had to close my output writer before reading from it, otherwise it blocks.
if (!socket.isOutputShutdown()) {
socket.shutdownOutput();
}
The answer came from a person who later deleted own answer :-/
I was trying this code. it works fine but if I remove \n in String str it doesn't work I mean It was able to compile without \n but it didn't give me output.
public class Test {
// Use try-with-resources to close a socket.
public static void main(String args[]) throws Exception {
int c;
// Create a socket connected to internic.net, port 43. Manage this
// socket with a try-with-resources block.
try (Socket s = new Socket("whois.internic.net", 43)) {
// Obtain input and output streams.
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
// Construct a request string.
String str = (args.length == 0 ? "MHProfessional.com" : args[0]) + "\n"; // <- herer
// Convert to bytes.
byte buf[] = str.getBytes();
// Send request.
out.write(buf);
// Read and display response.
while ((c = in.read()) != -1) {
System.out.print((char) c);
}
}
// The socket is now closed.
}
}
The server you're talking to reads data up until an end-of-line (\n) character -- that's just the way it works, but it's far from unusual. It's possible that other end-of-line sequences will be accepted as well.
The server has to have some way to know the client has finished sending data. It will probably know if the client closes its connection, but by then it's too late to respond to the client.
I'm trying to read the data back from a server program that I didn't write. The server program doesn't send any kind of end of transmission character and it doesn't close the socket once it sends a response. There is a button I can press on the server to close the connection manually and if I leave a little bit of a timeout on the (android)client side so I have time to press it, I do get the data from the server into my client app. Otherwise it just eventually times out and I get no response. Since I can't control the protocol on the server side how can I close the connection and get the response from the server? Thanks for any help.
cSocket.setSoTimeout(timeOut);
cOut = new PrintWriter(cSocket.getOutputStream(), true);
cOut.println(msgIn);
cIn = new BufferedReader(new InputStreamReader(
cSocket.getInputStream()));
int intTest;
while ((intTest = cSocket.getInputStream().read()) != -1) {
System.out.println(cIn.readLine());
Message from the server looks like this:
char(60)...char(62)char(60)...char(62)char(60)...char(62)char(60)...char(62)
... is random data inside the chars doesn't duplicate.
*Final edit
Got it working like this:
int c;
int intCount = 0;
StringBuilder response= new StringBuilder();
while ((c = cIn.read()) != -1) {
response.append( (char)c ) ;
if (c == 62) {
intCount = intCount + 1;
}
if (intCount >=4) {
cSocket.close();
String result = response.toString();
System.out.println(result);
break;
}
}
while ((intTest = cSocket.getInputStream().read()) != -1) {
System.out.println(cIn.readLine());
This doesn't make any sense. Just because you read a byte doesn't mean you can read another whole line, and you're throwing away the byte you did read. It should be:
while ((intTest = cSocket.getInputStream().read()) != -1) {
System.out.println(intTest);
And intTest is a poor name for an input byte. There's no 'test' about it. I would call it i, or b.
The JavaDoc for the class InputStream says the following:
Reads up to len bytes of data from the input stream into an array of
bytes. An attempt is made to read as many as len bytes, but a smaller
number may be read. The number of bytes actually read is returned as
an integer. This method blocks until input data is available, end of
file is detected, or an exception is thrown.
This corresponds to my experience as well. See for instance the example code below:
Client:
Socket socket = new Socket("localhost", PORT);
OutputStream out = socket.getOutputStream();
byte[] b = { 0, 0 };
Thread.sleep(5000);
out.write(b);
Thread.sleep(5000);
out.write(b);
Server:
ServerSocket server = new ServerSocket(PORT);
Socket socket = server.accept();
InputStream in = socket.getInputStream();
byte[] buffer = new byte[4];
System.out.println(in.read(buffer));
System.out.println(in.read(buffer));
Output:
2 // Two bytes read five seconds after Client is started.
2 // Two bytes read ten seconds after Client is started.
The first call to read(buffer) blocks until input data is available. However the method returns after two bytes are read, even though there is still room in the byte buffer, which corresponds with the JavaDoc stating that 'An attempt is made to read as many as len bytes, but a smaller number may be read'. However, is it guaranteed that the method will not block once at least one byte of data is read when the input stream comes from a socket?
The reason I ask is that I saw the following code in the small Java web server NanoHTTPD, and I wondered if a HTTP Request smaller than 8k bytes (which most requests are) potientially could make the thread block indefinately unless there is a guarantee that it won't block once some data is read.
InputStream is = mySocket.getInputStream();
// Read the first 8192 bytes. The full header should fit in here.
byte[] buf = new byte[8192];
int rlen = is.read(buf, 0, bufsize);
Edit:
Let me try to illustrate once more with a relatively similar code example. EJP says that the method blocks until either EOS is signalled or at least one byte of data has arrived, in which case it reads however many bytes of data have arrived, without blocking again, and returns that number, which corresponds to the JavaDoc for method read(byte[], int, int) in the class InputStream. However, if one actually looks at the source code it is clear that the method indeed blocks until the buffer is full. I've tested it by using the same Client as above and copying the InputStream-code to a static method in my server example.
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(PORT);
Socket socket = server.accept();
InputStream in = socket.getInputStream();
byte[] buffer = new byte[4];
System.out.println(read(in, buffer, 0, buffer.length));
}
public static int read(InputStream in, byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
}
else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}
else if (len == 0) {
return 0;
}
int c = in.read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len; i++) {
c = in.read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
}
catch (IOException ee) {
}
return i;
}
This code will have as its output:
4 // Four bytes read ten seconds after Client is started.
Now clearly there is data available after 5 seconds, however the method still blocks trying to fill the entire buffer. This doesn't seem to be the case with the input stream that Socket.getInputStream() returns, but is it guaranteed that it will never block once data is available, like the JavaDoc says but not like the source code shows?
However, is it guaranteed that the method will not block once at least one byte of data is read when the input stream comes from a socket?
I don't think this question means anything. The method blocks until either EOS is signalled or at least one byte of data has arrived, in which case it reads however many bytes of data have arrived, without blocking again, and returns that number.
I saw the following code in the small Java web server NanoHTTPD
The code is wrong. It makes the invalid assumption that the entire header will be delivered in the first read. I would expect to see a loop here, that loops until a blank line is detected.
I wondered if a HTTP Request smaller than 8k bytes (which most requests are) potientially could make the thread block indefinitely unless there is a guarantee that it won't block once some data is read.
Again I don't think this means anything. The method will block until at least one byte has arrived, or EOS. Period.
My question is similar to this post. But I don't send packet length rather a 0 byte at end.
Most efficient way to read in a tcp stream in Java
So I'm wondering how would I code something that would.
At the moment I just use
this.socketIn = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
String line = this.socketIn.readLine();
If packet is getting sent while you are spamming the packet it's going to count the packet which hasn't arrived yet as a fully read Line, yet it's incomplete and messes up the whole protocol.
In my protocol each packet is ended with a 0 byte (0x00) to determine the end of a single packet if in case packets end up merged/stacked together.
So what I'm trying to do really is keep reading the socket stream until a 0x00 is reached to indicate the packet is fully crafted and ready for processing.. and of course some kind of security (a timeout is best I believe) to determine the packet is junk as it's not ended in a 0 byte in a specific time frame lets say 5 seconds.
How would I go about doing this?
P.S>
I'm not using NIO framework but just a regular thread per connection socket and I don't want to switch to NIO as it's very difficult to inject data with a completely different global thread that processes updates and sends specific updates to random users (not broadcast).
Here is what I tried so far.
String line = "";
int read;
long timeOut = System.currentTimeMillis();
while(true) {
read = this.socketIn.read();
if (read == -1 || read == 0 || (System.currentTimeMillis()-timeOut) > 5000)
break;
line += read
}
Here's a sketch using setSocketTimeout to deal with the "slow client / denial of service" scenario.
this.socket.setSoTimeout(5000);
BufferedReader br = new BufferedReader(
new InputStreamReader(this.socket.getInputStream()));
StringBuilder sb = new StringBuilder();
try {
int ch;
while ((ch = br.read()) != -1) {
if (ch == 0) {
String message = sb.toString();
// process message
sb.setLength(0);
} else {
sb.append((char) ch);
}
}
} catch (InterruptedIOException ex) {
System.err.println("timeout!");
...
} finally {
br.close();
}
I think it is also possible to implement a (brutal) socket timeout by creating a second thread that calls socket.close() on the socket object if it detects that the reading thread is not getting any data. But that's a heavyweight approach, given the simpler setSoTimeout() approach.
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader in = new BufferedReader(isr);
String line = "";
String response = "";
while ((line = in.readLine()) != null) {
System.out.println(line);
response = response + line + "\n";
if (in.ready() == false) {
break;
}
}
The trick is the ready function that belongs to the BufferedReader. You need to check if it's ready, if not just get out of the loop.
Should I use StringBuilder? or build my own as EJP wrote. which is faster?
String line = "";
int read;
//long timeOut = System.currentTimeMillis();
this.socket.setSoTimeout(5000);
while(this.socket.isConnected()) {
read = this.socketIn.read();
if (read == -1)
throw new IOException("Insufficient data / timeout)");
else if(read == 0)
break;
line += (char)(read & 0xFF);
}