I have a problem where there is no IOException thrown when a Telnet client disconnects.
I used the server code from the following source:
http://java.sun.com/developer/onlineTraining/Programming/BasicJava2/Code/SocketThrdServer.java
From the given code, the server should terminate and display "Read Fail" when the client close. But it's not happening for Telnet or Putty (RAW connection). On the contrary, it works when I used the example Client given, it works perfectly.
I've also tried modifying the code so that readLine() doesn't block the I/O always, but using a timeout. However, it doesn't seem that it helped in detecting whether the Client has been disconnected.
while (true) {
try {
client.setSoTimeout(1000);
line = in.readLine();
// Send data back to client
out.println(line);
textArea.append(line);
} catch (SocketTimeoutException ex) {
if(client.isClosed()) {
System.out.println("Client disconnected");
System.exit(-1);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Read failed");
System.exit(-1);
}
}
Is there something missing from using Telnet or Raw Connection?
Edit: In addition to that, when I run 2 Clients, and then I close the first client, there would be no exception thrown from BufferedReader...
If it's a graceful shutdown, there should be no IO Exception.
in.readLine(); should return null in that case, a case your code should handle.
Related
I am trying to make a server (written in Python) and a client (written in Java) to communicate. The server code is the following:
import socket # Import socket module
connection=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection.bind(('',12800))
connection.listen(5)
connection_with_client, info_connection = connection.accept()
msg=b""
while(msg!=b"stop"):
print("Entering loop")
msg = connection_with_client.recv(1024)
connection_with_client.send(b"This is a message")
print("Sent")
connection_with_client.close()
connection.close()
The client code is:
try {
socket = new Socket(InetAddress.getLocalHost(),12800);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.print("stop");
out.flush();
System.out.println("Sent");
in = new BufferedReader (new InputStreamReader (socket.getInputStream()));
String message_from_server = in.readLine();
System.out.println("Received message : " + message_from_server);
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The strange thing is: when the client sends the message "stop", everything goes fine, message from server is received by the client. Now, when the client sends another message than "stop", the server tells it has sent the message, and enters the loop a second time, however the client never receives the message and gets stuck at the in.readLine() instruction.
I really don't get why as the first passage in the loop should have the same effects in both situations... Any help welcome!
On client side you are using readLine. Obviously, this reads the line, but how it detects where the line ends? The answer is:
you server should append line ending to all messages you send to client.
Try append b'\r\n' or whatever are lineendings on your OS. As far as readLine is called on client side, you should append line ending of a client, not server OS.
For Windows it is b'\r\n'
For Linux b'\n'
I can set up client Socket to send request to server (sendData() method) and read the received message (readData() method) correctly, but I only received message each time I send the request to server by using MOBILE_REQUEST string, through these codes:
#Override
protected Boolean doInBackground(String... params) {
try {
mSocket = new Socket(
// PC Ip is 192.168.1.199
// It is the other device, Not be local host : 127.0.0.1
Pas.pas.getPcIP(), 17001);
DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());
String RESPONSE = null;
String MOBILE_BLOCK = "MobileBlock#";
// Converting collected data in byte array into String.
RESPONSE = sendData(mDos, MOBILE_BLOCK);
/**
* The result response from PC app in here
*/
// Log : response - #WindowsResp#192.168.1.199#
Log.i("", "response '" + RESPONSE + "'");
}
} catch (SocketTimeoutException e) {
IS_SOCKET_TIME_OUT = true;
e.printStackTrace();
} catch (ConnectException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
sendData() method - Client send the request to server and wait to get response data - String data.
private String sendData(DataOutputStream mDos, String MOBILE_REQUEST) {
try {
// Log : MOBILE_REQUEST.getBytes() - [B#82f10f8
mDos.write(MOBILE_REQUEST.getBytes());
// todo I should set this sleep, bcs TCP has delay time,
// so i need set the delay time for client should receive data
// otherwise, sometimes I did not receive anything
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Log : #WindowsResp#192.168.1.199#
return new String(readData(mSocket));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
readData() method - Read data after received from server.
public static byte[] readData(Socket mSocket) {
/* Since data are accepted as byte, all of them will be collected in the
following byte array which initialised with accepted data length. */
DataInputStream mDis = null;
try {
mDis = new DataInputStream(mSocket.getInputStream());
// Log : mDis.available() - 23
byte[] data = new byte[mDis.available()];
// Collecting data into byte array
for (int i = 0; i < data.length; i++)
data[i] = mDis.readByte();
// Log : data - [B#30c044a4
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
What I want is every time server send to my socket client the message by clicking button, the socket client should receive it. But in above codes, it's not.
Please help me how to set up socket client always listen from server?
p/s : Or do I need set up ServerSocket? If use ServerSocket I cannot use same port, right? Because when I open ServerSocket for listen first (ex. at port 17001), I can not use client socket to send request via port 17001 because that port is already used.
UPDATED
The way server (PC app - laptop device) send to client (Mobile device - Android) is via Socket TCP, through these steps :
1 - Client (Android device) set up TCP socket connection to Server (PC app) (this connection never closed until exit app in onDestroy() method).
2 - Client send request to server, ex. MOBILE_REQUEST = "MobileID#MobileIP#"
3 - Server received the request from client, It replied to client via Socket connection, actually client received data correctly. ex. "WindowsRep#WindowsIP"
This way not work for me, even socket TCP connection not closed, and getInputStream() not shut down yet. In this case :
Server send string data to client via Socket connection, client received data correctly.
What I want is every time "Server send string data to client via Socket connection, client received data correctly". But in my case, client only receive data after sent request to server.
C# Server
Server socket
IPEndPoint ipe = new IPEndPoint("192.168.1.199", 17001);
svSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
svSocket.Bind(ipe);
Server Send data
string data_send = "#WBroad#" + "192.168.1.199" + "#";
byte[] byteData = Encoding.UTF8.GetBytes(data_send);
c.ClientSocket.Send(byteData);
As you haven't posted the sending code it is impossible to tell why you're not receiving data, but here is a quick critique of what you have posted:
// mSocket.setReuseAddress(true);
You've commmented this out, but it would be pointless to call this method now. You would have to construct the socket as new Socket(), with no parameters, then call this method, then call connect(). And as you aren't providing a source port or IP address to be re-used, it would still be pointless.
byte[] data = new byte[mDis.available()];
This is a complete misuse of available(). It does not provide a message length. See the Javadoc. There is no reason to believe that whatever data has arrived at this point, if any, is a complete message, or only one message. If you want messages you won't get any help from TCP: you will have to implement them yourself. As your protocol appears to be text-based I suggest you just use lines and readLine(), with BufferedReader and BufferedWriter instead of the DataInput/OutputStreams. And construct those once for the life of the socket, not once per application message, otherwise you will lose data.
// Collecting data into byte array
for (int i = 0; i < data.length; i++)
data[i] = mDis.readByte();
The huge problem with this is that it won't block, because, most of the time, available() will be zero, so this method will do nothing except return an empty byte[] array.
In any case this is entirely equivalent to mDis.readFully(data);, only several times less efficient, but you shouldn't be doing this anyway: see above.
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
This is poor practice. You should let the IOException be thrown by this method and let the caller deal with it.
mDos.write(MOBILE_REQUEST.getBytes());
See above. This should include a line terminator, a length-word prefix, or some other way of delimiting the message.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
This sleep is literally a complete and utter waste of time. And space. Remove it. Sleeping in networking code is just cargo-cult programming.
return new String(readData(mSocket));
This will throw a NullPointerException if readData() returns null, which it does if there was an IOException, which is another reason to let that method propagate that exception instead of catching it internally and returning null.
private boolean splitData(int mobile_send_request_case, String DATA) {
This method is entirely irrelevant to the problem and should not have been posted.
Or do I need set up ServerSocket?
No. Why do you think that?
If use ServerSocket I cannot use same port, right?
Wrong.
Because when I open ServerSocket for listen first (ex. at port 17001), I can not use client socket to send request via port 17001 because that port is already used.
Wrong again. It isn't.
As I said above, it's impossible to help you further when you don't post all the relevant code, but there's enough wrong with this already that you really need to start again.
I want to write a HTTP server with a long time response.
I prepared a loop:
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8000));
while (serverSocketChannel.isOpen()) {
try {
System.out.println("Waiting...");
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("The new connection is open ;)");
} catch (IOException ex) {
System.out.println(ex.getMessage());
Logger.getLogger(ServerHttp.class.getName()).log(Level.SEVERE, null, ex);
}
}
I want to catch new connection from a user's browser, put it into a list, and then another thread will take it and will parse it.
But I have problem on the beginning: the code above is freezing in the method serverSocketChannel.accept().
When I add socketChannel.close() everything is working correctly, but I don't want to close the connection in this place, because I need a long time response.
Look at the javadoc for ServerSocketChannel:
"If this channel is in non-blocking mode then this method will immediately return null if there are no pending connections. Otherwise it will block indefinitely until a new connection is available or an I/O error occurs."
This seems to describe the "freezing" you are experiencing.
You can open your ServerSocketChannel in non-blocking mode:
serverSocketChannel.configureBlocking(false);
The below program causes this issue
EDITED:
import java.io.*;
import java.net.*;
public class smtpClient {
public static void main(String[] args) {
// declaration section:
// smtpClient: our client socket
// os: output stream
// is: input stream
Socket smtpSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
// Initialization section:
// Try to open a socket on port 25 : step 1
// Try to open input and output streams: step 2
try {
smtpSocket = new Socket("192.168.1.2", 1024);
os = new DataOutputStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());
} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
// If everything has been initialized then we want to write some data
// to the socket we have opened a connection to on port 25
if (smtpSocket != null && os != null && is != null) {
try {
// The capital string before each colon has a special meaning to SMTP
// you may want to read the SMTP specification, RFC1822/3
os.writeBytes("HELO\n");
os.writeBytes("MAIL From: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("RCPT To: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("DATA\n");
os.writeBytes("From: k3is#fundy.csd.unbsj.ca\n");
os.writeBytes("Subject: testing\n");
os.writeBytes("Hi there\n"); // message body
os.writeBytes("\n.\n");
os.writeBytes("QUIT");
// keep on reading from/to the socket till we receive the "Ok" from SMTP,
// once we received that then we want to break.
String responseLine;
while ((responseLine = is.readLine()) != null) {
System.out.println("Server: " + responseLine);
if (responseLine.indexOf("Ok") != -1) {
break;
}
}
// clean up:
// close the output stream
// close the input stream
// close the socket
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
}
Console Log :
Couldn't get I/O for the connection to: hostname
The program I took is from :
http://www.javaworld.com/jw-12-1996/jw-12-sockets.html?page=4
I have already tried modifying the port from 25 to 1024
I am running it on my local PC, so I am admin on this system, but not sure if there is any default firewall issue(running this in eclipse on windows 7)
As per your comments below : DO I need to make a listner, which mean to say a Server Socket, which will listen to smtp client requests
Answer is: according to details what you have provided, there is no listener running or machine with specified IP and port number.
UPD: then you are trying to connect to somewhere you do have to be sure that there is something which listens on other side, either writing your own server code or by using a 3rd party server/code to provide certain service on a port number you are trying to reach.
Why would you expect that there is a mail server running on machine with an address you've provided?
It sounds like some other program is using port 1024.
Try a different port.
I try to overcome a user disconnection detection on the server side using read timeout.
This is part of my code:
try {
socket.setSoTimeout(3000);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
usr = new User(in.readUTF());
usr.connectUser();
int i=0;
while(true){
try{
i = in.readInt();
}
catch(SocketTimeoutException e){
System.Out.Println("Timeout");
// user connected, no data received
}
catch(EOFException e){
System.Out.Println("Disconnected");
// user disconnected
}
}
}
catch(Exception e){
// other exceptions
}
the code works fine except the "user disconnected" issue.
i want to catch the timeout exception and just continue waiting for data
but only if the client still connected.
why i never get other exception than SocketTimeoutException?
shouldn't i get IOException while in.readInt() can't use the socket because client disconnected?
is there any other simple way to detect user disconnection?
i mean as unwanted disconnection, like user had suddenly wifi shutdown etc...
thanks,
Lioz.
If the client didn't write anything within the timeout period, you get a SocketTimeoutException. If he disconnected instead of writing anything, you get an EOFException. Catch them separately. If you didn't get an EOFException, he didn't disconnect.