Please help me out on how to read the stream of data in java. My requirement is to make the telnet connection to the router. This part is accomplished. From the router, Have to connect to the xxx remote machine using its ip address and port number through telnet. While making this connection, i am getting some response. But while reading, the program control stops at read() method of InputStream class. Here are the code snippet which i am using to read the stream of data.
buff = new byte[4*1024];
ret_read = 0;
do
{
ret_read = in.read(buff); // Program control gets hanged here. Once all the data are read...
if(ret_read > 0)
{
System.out.println(new String(buff,0,ret_read));
}
}while(ret_read > 0);
What is happening is the read is blocking and waiting for more data to be sent on the stream, it will continue to do that until the stream is closed or more data is sent.
You need to either use a non-blocking read, put a timeout on the read, or close the stream server side after it finishes sending the data.
Related
I have been trying to send a byte[] array across my client / server application using Sockets, DataInputStream and DataOutputStream, but on the server side, the program just gets stuck when I try to initialise the DataInputStream.
Here is the code on the client side (it works fine):
DataOutputStream datas = new DataOutputStream(connection.getOutputStream());
datas.flush();
byte[] send = identityKeyPair.serialize();
datas.write(send);
datas.flush();
Here is the code on the server side:
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()) );
sender = new PrintWriter(connection.getOutputStream());
newUser = new BasicUserData();
System.out.println("New registration from: " + connection.getInetAddress());
System.out.println("Data:");
String un = reader.readLine();
newUser.USERNAME = un;
System.out.println(newUser.USERNAME);
String pw = reader.readLine();
newUser.PASSWORD = pw;
System.out.println(newUser.PASSWORD);
DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
System.out.println("Opened data output stream");
DataInputStream receiver = new DataInputStream(connection.getInputStream());
//It gets stuck here, and the program doesn't read anything further
receiver.read();
byte[] id = receiver.readAllBytes();
System.out.println("Opened data input stream");
You are using both connection.getInputStream() and connection.getOutputStream() in two different ways. You should use one and only one way of reading from and writing to streams, don't mix multiple ways.
When you execute reader.readLine(), the BufferedReader called reader will read up-to 8192 characters from the input stream into its buffer, likely consuming all bytes your client has written. This means that when you construct your DataInputStream around that same input stream and try to read it, there is no data available to read, causing the receiver.read() to block waiting for data. That data is never received as your client has sent all its data, which is now buffered in reader.
In addition, unless your client has closed its output stream, InputStream.readAllBytes() will block indefinitely anyway, because it is only finished when the end-of-stream has been reached. And for socket communication, that only happens when the other side closed its output stream.
Change your code so there is only one way of writing data (though not relevant here), and one way of reading data. In addition, you should establish clearly how you need to read and write data in a protocol, so to avoid consuming too much data at the wrong point, and to know how much data you need to read when.
Of course it does nothing but wait as specified in the javadoc a call to DataInputStream#read() blocks the current thread until data can be read from the input stream.
Your reader = BufferedReader(...) uses the same underlying InputStream which means the all the data the client sent is most likely already consumed by the 'login' logic.
Since neither the client nor the server close their respective streams no EOF is emitted either which leads to the stream 'just dangling' around waiting for more data.
Unless your client sends more data the server will wait eternally.
There are two solutions for your issue.
Either thread you application so that the 'await input' logic is in it's own thread or take a look at javas NIO package (more precisely Channels and Selectors)
I am trying to set up a program where the server can communicate with multiple clients. The program is written in Java. I got it all working on the same machine so I decided to try LAN. I converted the program to JAR files and I tried connecting my laptop to my PC (both are on the same network). The connection is successful but unfortunately only 1 message arrives to the server. As you can see in the code below, I send multiple messages (Meaning that i write multiple times) via DataOutputStream. One defines the datatype (in the following example 0 means that it's a String) and the other sends the actual message data. I also print the size of the packets in bytes and it always matches the size of the DataOutputStream instance.
DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
String str = "Hello";
//Type
System.out.println("Type output size: 1");
dOut.writeByte(0);
//Message
System.out.println("Message output size: " + (str.getBytes(StandardCharsets.UTF_8).length + 2));
dOut.writeUTF(str);
System.out.println("Length of all: " + (dOut.size()));
dOut.flush();
So now when the data from the client is sent we need to handle it on the server, which the code below does. It retrieves the InputStream from the Socket called client and inserts it into the DataInputStream. This is were it gets weird on LAN as the stream only contains the first message.
InputStream stream = client.getInputStream();
DataInputStream dIn = new DataInputStream(stream);
while(dIn.available() > 0) {
byte type = dIn.readByte();
switch(type) {
case 0:
System.out.println(dIn.readUTF());
break;
case 1:
System.out.println(dIn.readInt());
break;
case 2:
System.out.println(dIn.readByte());
break;
default:
throw new IllegalStateException("Unexpected value: " + type);
}
}
If you run the Client in the IDE on lets say a laptop connected to the same network and then you run the Server on a PC connected to the same network it will work. However, not if the programs are in JARS.
The actual stacktrace is the following:
java.net.SocketException: Connection reset
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961)
at
java.base/java.io.DataInputStream.readInt(DataInputStream.java:393)
The stacktrace does not tell me anything, but it points at case 0: in the switch case. It can't read the String as the DataInputStream does not contain any data (I guess?).
I would also like to state that the Server is multithreaded! I have one thread that adds the sockets when they are accepted through ServerSocket.accept() and I use the second (main thread) to read the data sent from clients.
I have selected the code above as I believe that the issue lies within it, however I am new to Socket Programming and I know that some of you would like to see other parts of the code. I will add more relevant code when I am asked.
I do not know why it acts like this, does anyone know why?
What have i tried?
I have tried waiting for packets - but that has only resulted in the
Server looping forever. With waiting for packets I mean not going forward until the DataInputStream contains enough bytes.
I have disabled Nagels Algorithm through setTCPNoDelay(false).
Tried to send different datatypes, but that also failed
I tried changing the first packet to a String which resulted in the String showing up in the DataInputStream.
I have tried portforwarding the port used and I have tried disabling the firewall on both computers.
Update 1
I have been taking advice from the comments which has led a to a few discoveries:
Closing the DataOutputStream successfully sends all packets to the client.
It is also possible to build your own buffer and decode it in the server. However, it is still not possible to send any more messages after this.
It worked as a JAR because IntelliJ was being nice (Eclipse threw the same error when running in IDE)
Update 2:
I think this post is relevant. It states that SocketException is sent when a client closes it's socket "ungracefully". And because my Client closes (as it is not in a loop) and I don't close the socket properly - it will close "ungracefully" and the data will be lost. Hence the error.
The issue is now solved, and the solution is quite logical. My client does not operate in a loop, rather it sends the data and closes the program. That sounds fine, but I forgot to properly close the socket of the client.
The reason why the second 'packet' never arrived was due to me doing this tiny mistake. The packet was on it's way through the local network but the client socket improperly closed it's socket before the packet arrived to the server, which is why I got a SocketException error. See this.
I solved the issue by putting socket.close() ,where socket is the client's socket, after I had sent all the messages I wanted to send.
I used the Android's ToyVpnClient to set up a tunnel and intercept incoming & outgoing packets. I want to write these packets from this tunnel, which is stored in a ByteBuffer, to a pcap file. I've looked at jpcap and jnetpcap, but they seem to only support creating the pcap file from the packets that were captured by using these libraries to listen to the device's network interfaces in the first place.
Is there any api available that would help me create the pcap file from the tunnel's packet data stored in the ByteBuffer? If I were to create my own pcap writer, how would i go about parsing this packet from the tunnel and put it into the pcap format? (I've looked but haven't found any examples)
Here's the relevant code sample from the ToyVpnClient:
...
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server.
tunnel.connect(server);
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// keep forwarding packets till something goes wrong.
while (true) {
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
//How to write to pcap file here?
packet.clear();
}
...
}
Thank you
For anyone looking for similar solution, I got it working using the netutils library's PCapFileWriter and modifying it to include a fake ethernet header for each packet (http://code.google.com/p/netutils/)
I am using Java to implement a multithreaded TCP server-client application. But now i have encountered a strange problem: when i shutdown the server socket, the receiver can still receives the last sent packet continuously. Since the detail of socket read is of the kernel concern, i can't figure out the reason. Can anybody give some guideline?
Thanks in advance!
Edit:
The code involved is simple:
public void run() {
while(runFlag) {
//in = socket.getSocketInputStream();
//byte[] buffer = new byte[bufferSize];
try {
in.read(buffer);
//process the buffer;
}catch(IOException e) {
//
}
}
}
when shutdown the server socket, this read operation will receive packet continuously(each time enters the while loop).
The TCP/IP stack inside the OS is buffering the data on both sides of the connection. Sender fills its socket send buffer, which is drained by the device driver pushing packets onto the wire. Receiver accumulates packets off the wire in the socket receive buffer, which is drained by the application reads.
If the data is already in the client socket's buffer (kernel-level, waiting for your application to read it into userspace memory), there is no way for the server to prevent it from being read. It's like with snail mail: once you've sent it away you cannot undo it.
That's how TCP works. It's a reliable byte-stream. Undelivered data continues to be delivered after a normal close. Isn't that what you want? Why is this a 'problem'?
I am currently working on a simple proxy server, which receives http request from browser, process it, then forward it to the desire web server.
I try to get the request from the input stream of the socket connected by the browser, everything is fine except that the stream get stuck after receiving the last block of data.
My code is in fact very simple, as shown below:
ServerSocket servSocket = new ServerSocket(8282);
Socket workSocket = servSocket.accept();
InputStream inStream = workSocket.getInputStream();
byte[] buffer = new byte[1024];
int numberRead = 0;
while ((numberRead = inStream.read(buffer, 0, 1024)) != -1){
System.out.println(new String(buffer));
}
The loop simply cannot exit, even the request reception is finished.
Is there any method to workaround this problem?
Thanks in advance for any advice.
As in InputStream javadoc the method will block until the data is available or the EOF is encountered. So, the other side of Socket needs to close it - then the inStream.read() call will return.
Another method is to send the size of message you want to read first, so you know ahead how many bytes you have to read. Or you can use BufferedReader to read from socket in line-wise way. BufferedReader has a method readLine() which returns every time a line is read, which should work for you as HTTP protocol packages are nice divided into lines.
It will cycle until the connection is closed, and the client is probably waiting for HTTP response from you and doesn't close it.
The browser is waiting for a response before it closes the connection.
Your read-method on the other hand will block until the stream/connection is closed or new data is received.
Not a direct solution according to your current code.
As HTTP is a line based protocol, you might want to use a Buffered Reader and call readLine() on it.
The when a http request comes in it will always be concluded with a blank line, for example:
GET /someFile.html HTTP/1.1
Host: www.asdf.com
After sending that request the client connection will then wait for a response from the server before closing the connection. So if you want to parse the request from the user you are probably better off using a BufferedReader and reading full lines until you reach a lines of text that is blank line.