When the server socket is closed the client doesn't receive any exception even after writing on the OutputStream and the server socket is already close.
Giving the following classes to test that:
public class ModemServerSocket {
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket serverSocket = new ServerSocket(63333);
Socket client = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
String s;
while ((s = reader.readLine()) != null) {
System.out.println(s);
if (s.equals("q")) {
break;
}
}
serverSocket.close();
}
}
public class ModemClientSocket {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket("localhost", 63333);
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
String[] sArray = {"hello", "q", "still there?"};
for (String s : sArray) {
writer.println(s);
if (s.equals("q")) {
Thread.sleep(5 * 1000);
}
}
System.out.println("Whoop. No exception. The client didn't notice.");
}
}
What I did was to launch the ModemServerSocket application then after that I launched the ModemClientSocket application.
ModemServerSocket Output:
hello
q
ModemClientSocket Output:
Whoop. No exception. The client didn't notice.
Is this the expected behavior? Why is happening this?
However I did another test where I close the ModemClientSocket and the ModemServerSocket tries to read from the InputStream in that case I got an java.net.SocketException which is what I expected. The weird thing is that is not happening for the PrintWriter (OutputStream) and no exception is thrown.
I used Java 1.6.0 Update 26 for the tests.
Quoting the JDK documentation of PrintWriter below.
Methods in this class never throw I/O exceptions, although some of its constructors may. The client may inquire as to whether any errors have occurred by invoking checkError().
PrinterWriter Documentation
I believe that closing the ServerSocket just means that no new connections will be accepted -- it doesn't close connections that have already been set up (You'd need to call client.close() in ModemServerSocket to do that).
Based on some tests I ran, even if you don't use PrintWriter, and instead write directly to socket.getOutputStream(), I don't think you're guaranteed an exception when the server closes its socket, but if you call write() enough times it seems that eventually you will get an exception.
Note that there is sometimes a difference in behavior depending on whether the client and server are on the same machine or not. When running locally, fewer writes seem to be needed before the "SocketException: Broken pipe" exception happens.
If you want to realiably detect that the socket is closed you need to read from it, and check whether the read returns -1. (and, of course, handle any exceptions)
For example:
if (socket.getInputStream().read(bytearray) < 0)
break;
If the server isn't sending anything you can hack things up by calling socket.setSoTimeout(1), and handling/ignoring the SocketTimeoutException, but the "right" way to do it is probably to start with SocketChannel instead of Socket so you can use a Selector which should notify you when the read() method can be called.
btw, the serverSocket.close() line is a bit misleading, and should probably be client.close(). However, the class exits immediately after that, so all sockets will be closed anyway.
Related
=========Menu Bagian Server=========
1. Start Server
2. server room
2. Exit
=============================================
Masukkan Pilihan: masukkan angka!
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
at com.company.Server.menuServer(Server.java:35)
at com.company.Server.main(Server.java:17)
Process finished with exit code 1
here is the code, how to make the menu loop again so i can start the server after it terminated
public static void serverRoom() throws IOException{
din = new DataInputStream(s.getInputStream());
dout = new DataOutputStream(s.getOutputStream());
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
String str = "", str2;
while (!str.equalsIgnoreCase("Exit")) {
str = din.readUTF();
System.out.println("client says: " + str);
str2 = br.readLine();
dout.writeUTF(str2);
dout.flush();
}
din.close();
s.close();
ss.close();
}
InputStreamReader and BufferedReader are so-called filter streams: They don't themselves represent a resource that must be closed; they wrap around some other resource.
The rule is, if you close a filterstream, it closes the thing they wrapped. (So, calling close() on br will cause that bufferedreader to invoke close() on that new InputStreamReader object, which in turn causes it to call close on System.in.
Here's the thing, while usually you want to always close resources, you do not want to close System.in!
You are, here, by using the try construct.
Solution: Just.. do not do that. Do not make a try() {} block here.
Your IDE might complain. Tell it to shut up, it is wrong.
You get this error because the code closes System.in (by reaching the end of the try-with-resources block, which invokes close() on the resource, which invokes close() on the ISR, which invokes close() on System.in), and once it is closed, no further lines can be read from it.
The following question I have is pretty straightforward.
Here is my code:
public class Protocol implements Runnable {
private SSLSocket socket = null;
private InputStream is = null;
private OutputStream os = null;
...
public Protocol(Socket s) {
socket = (SSLSocket)s;
is = socket.getInputStream();
os = socket.getOutputStream();
}
#Override
public void run() {
...
ping();
socket.close();
...
}
public void ping() {
BufferedWriter writer;
try {
writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write("OK");
}
catch (IOException e) { System.out.println("ERROR: " + e.getLocalizedMessage()); }
finally { writer = null; }
}
I understand I didn't include a lot of source code, but this should be enough to answer the question. As you can see, in the "ping" method I have a BufferedWriter which I create to write an "OK" string to the remote source. Later on, I close the Socket.
So my simple question is this - From what I understand, since I close the socket, the chain should go like this:
Close socket ----> which closes is and os ----> closes writer
So, by closing the Socket, I am also closing and allowing the BufferedWriter to be freed by the GC. Am I understanding this correctly or doing something wrong? Is this true for all writers and readers that I initialize in other methods (i.e. BufferedInputStream). And by setting these variables null at the end of the method, am I helping the GC to distinguish between what should be freed? Or should I not do this?
Thanks!
From what I understand, since I close the socket, the chain should go like this:
Close socket ----> which closes is and os ----> closes writer
No. The BufferedWriter is wrapped around the socket output stream, but the socket doesn't know that. It has no way of closing it.
So, by closing the Socket, I am also closing and allowing the BufferedWriter to be freed by the GC.
No and no. The BufferedWriter is available for GC as soon as ping() returns, and it is never closed at all.
Am I understanding this correctly
No.
or doing something wrong?
Yes. You shouldn't create a new BufferedWriter per message. You should use the same one for the life of the socket, and close it instead of the socket. Similarly you should only use one input stream or Reader for the life of the socket. Otherwise you can lose data in their buffers.
Is this true for all writers and readers that I initialize in other methods (i.e. BufferedInputStream).
No.
And by setting these variables null at the end of the method, am I helping the GC to distinguish between what should be freed?
No. You are just wasting time and space. The method is about to exit anyway, so all its local variables disappear.
Or should I not do this?
You should not do any of it.
I tried to make a console chat server. the main problem i am facing is that i can not send the message to the server.. as you can see in the img i uploaded that the server and the client are connected. but when i type anything in the client side. The client becomes unresponsive and i have to close the cmd prompt.
How can i fix this?
Is something wrong with my computer or is the code wrong?
public class MyClient
{
Socket s ;
DataInputStream din ;
DataOutputStream dout;
public MyClient()
{
try
{
s= new Socket("localhost",10);
System.out.println(s);
din = new DataInputStream(s.getInputStream());
dout= new DataOutputStream(s.getOutputStream());
ClientChat();
}
catch(Exception e)
{
System.err.println(e);
}
}
public void ClientChat() throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Scanner s2 = new Scanner(System.in);
String s1;
System.out.println("start the conversation");
do
{
s1=br.readLine();
//s1=s2.nextLine();
dout.flush();
System.out.println("server:"+din.readUTF());
}
while(!s1.equals("stop"));
}
public static void main (String args[])
{
new MyClient();
}
}
The code snippet never calls dout.write*(), so nothing is ever sent over the Socket.
readLine() will block until a line of text is read, so messages sent to the client won't be printed until after the client types a 2nd line of text. You can fix this either by using asynchronous I/O or by moving the read loop into it's own Thread.
You need to make the server and client a thread, so they can work independently.
server as thread will wait for a client connections and will receive messages.
client as thread will work on its own.
problem is that they cannot run concurrently.
Use dout.writeUTF(s1); inside the do loop.
The writeUTF will allow you to write the subsequent message till then It will be stuck at readutf function.
The java.io.DataOuputStream.writeUTF(String str) method writes a string to the underlying output stream using modified UTF-8 encoding. Refer to this
I'm using TelnetClient.class from Apache Commons Net 3.3 jar. My problem is that the behavior of the method setSoTimeout() is not what is expected. This method, as far as i know, simply calls the one with the same name but in the Socket.class setting the read() timeout. This is a sample code (IOManager is just a class i made for I/O operations):
telnet = new TelnetClient();
telnet.connect("localhost", 2020);
telnet.setSoTimeout(10000);
manager = new IOManager(telnet.getInputStream(), telnet.getOutputStream());
while (true) {
System.out.println(manager.readBuffer());
Thread.sleep(10000);
manager.sendMessage("Peanut Butter Jelly");
}
And this is the code of the method i use to read in IOManager class (reader is a BufferedReader with the telnet inputstream which has the soTimeout enabled):
public String readBuffer() throws IOException {
StringBuilder message = new StringBuilder();
int len;
char[] chars = new char[1024];
do {
if ((len = reader.read(chars)) != -1) {
message.append(chars, 0, len);
Thread.sleep(30);
} else {
throw new IOException("Stream closed");
}
} while (reader.ready());
return message.toString();
}
My problem is: even when im not calling the read() in the moment the timeout seconds are counting! All i want is to attempt to read data for 10 seconds but when i read something and then i wait 10 seconds and write, when i attempt again to read BOOM! java.net.SocketTimeoutException: Read timed out.
The timeout is expiring instantly! The server side then throw this: java.net.SocketException: Software caused connection abort: recv failed
The processes i work with do a lot of things before reading again, even waiting more than 20 minutes before sending a command again. The application must restart when it doesn't get an answer in the specified timeout. If i delete the Thread.sleep() it reads and sends correctly, as long as the client could not read data in 10 seconds (normal)
I work a lot with Server/Client programs and Sockets. This is only happening when using the TelnetClient. What could be the problem? Why this behavior? If i can't get it to work i think im going to use Callabe and Future interfaces but that is another Thread just to read (ouch, im actually making multiple connections to that Telnet Server).
Thanks for reading.
I ran into this problem and solved it by turning off the reader thread in TelnetClient:
telnet = new TelnetClient();
telnet.setReaderThread(false); // This prevents the timeout bug
telnet.connect("localhost", 2020);
telnet.setSoTimeout(10000);
I couldn't find a way. The behavior was always unexpected so i did it with this code:
I have my ExecutorService with space for only 1 Thread. I implement the call() method from Callable generic interface (that's why i can return String or whatever i want).
ExecutorService executor = Executors.newFixedThreadPool(1);
Callable<String> readTask = new Callable<String>() {
#Override
public String call() throws Exception {
return readBuffer();
}
};
I overload the readBuffer() method. I have this one that reads acepting a timeout argument:
public String readBuffer(long timeout) throws ExecutionException, TimeoutException {
return executor.submit(readTask).get(timeout, TimeUnit.MILLISECONDS);
}
The executor submits the task reading the buffer until there's nothing else to read or until the timeout in milliseconds expires.
It works as expected and without performance problems.
I am feeling really stupid right now guys.... basically I am connecting over TCP on a local machine... and when I try to make the In/out streams at the client it wont get passed creating the object input stream. What gives? This stops after printing 2... no exceptions or anything... This isn't the first time I've used this class which is partialy why I am puzzled.
try {
System.out.println("1");
mySocket = new Socket("localhost", 11311);
System.out.println("12");
oos = new ObjectOutputStream(mySocket.getOutputStream());
System.out.println("2");
ois = new ObjectInputStream(mySocket.getInputStream());
System.out.println("13");
} catch (Exception e) {
e.printStackTrace();
}
From the specification of ObjectInputStream:
This constructor will block until the corresponding ObjectOutputStream
has written and flushed the header.
(For future readers:) I had the same problem because i made a silly change in server program and didn't test it for a long time then i was confused about why program is locked.
ServerSocket accepts the connection (responderSocket = serverSock.accept();) then suddenly for a inapropriate if (The silly change i mentioned!) program jumps out of the thread and because i didn't add a finally block to close streams and sockets the socket was left abandoned w/o sending or recieving anything (even stream headers). So in client side program there was no stream header (When i debbugged The code i saw that the last function executed before lock was:
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
enableOverride = false;
readStreamHeader(); //// <== This function
bin.setBlockDataMode(true);
}
readStreamHeader();)
So be careful about what happens in server side, maybe problem isn't where you expecting it!