So I have this simple server. What I want to do is keep the server running and waiting for another client, when I kill the clients socket (telnet -> end process).
private ServerSocket serv;
public Server() throws IOException {
try {
serv = new ServerSocket(port);
serv.setReuseAddress(true);
while(true) {
Socket sock = serv.accept();
try {
BufferedReader netIn = new BufferedReader(new InputStreamReader(sock.getInputStream()));
PrintWriter netOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())), true);
while(true) {
//do stuff
}
} finally {
sock.close();
}
}
} catch (SocketException e) {
recreateSocket();
} catch (IOException e) {
e.printStackTrace();
}
}
private void recreateSocket() {
try {
ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(port);
serv = socket;
} catch (IOException e) {
e.printStackTrace();
}
}
Atm it throws bindException, how to deal with it.
Add catch statement(s) to before the finally block (but don't call recreateSocket() there )
Update to clarify, something like this:
while(true) {
//do stuff
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
sock.close();
Start a new thread to handle each accepted connection.
The reason is that you are creating a server socket again. You don't need to do this (the previous one is still working which is why you get a bind exception). This is what you want to do:
private ServerSocket serv;
public Server(int port) throws IOException
{
try {
serv = new ServerSocket(port);
serv.setReuseAddress(true);
while(true) {
Socket sock = serv.accept();
try {
BufferedReader netIn = new BufferedReader(new InputStreamReader(sock.getInputStream()));
PrintWriter netOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())), true);
// do stuff
} catch(SocketException e) {
e.printStackTrace();
} finally {
sock.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Related
In a simple Server Client communication I always get the "java.net.SocketException: Connection reset" on the serverside, if the client does not close the outputstream of it's socket directly after sending out the data via BufferedWriter.
If I close the client's outputstream everything works fine.
But obviously the client wants eventually to send more than one String (then the server needs to handle the connection in a new Thread). But I don't even get that far, because ofe the problem above...
Thanks for helping!!
Here is some condensed code to show the problem.
This is the server class:
public class TestServerCharacterStream {
public static void main(String[] args) {
System.out.println("### Started");
TestServerCharacterStream testServerCharacterStream = new TestServerCharacterStream(9498);
testServerCharacterStream.waitForData();
System.out.println("### Terminated");
}
private int port;
private ServerSocket serverSocket;
private BufferedReader in;
public TestServerCharacterStream(int port) {
this.port = port;
try {
this.serverSocket = new ServerSocket(port);
System.out.println("[SERVER] : Server started!");
} catch (IOException e) {
System.err.println("Cannot open new server socket!");
e.printStackTrace();
}
}
public void waitForData() {
Socket clientSocket = null;
try {
System.out.println("[SERVER] : Wait for data on port " + port + " ...");
clientSocket = serverSocket.accept();
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String incoming = in.readLine();
System.out.println("[SERVER] : Incoming message: " + incoming);
} catch (IOException e) {
System.err.println("Error while accepting connection or reading input!");
closeStreamAndSocket(clientSocket, in);
closeServerSocket();
e.printStackTrace();
}
}
private void closeStreamAndSocket(Socket socket, BufferedReader in) {
try {
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
System.err.println("Cannot close stream or socket.");
e.printStackTrace();
}
}
private void closeServerSocket() {
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
System.err.println("Cannot close serverSocket.");
e.printStackTrace();
}
}
}
This is the Client Class:
As mentioned, it works if closing the outputstream (see the comment). To use flush() or not does not make any difference. The only way to solve it is out.close();
But I want to use the BufferedWriter again, withot connect always again to the server.
public class TestClientCharacterStream {
public static void main(String[] args) {
System.out.println("### Started");
TestClientCharacterStream testClientCharacterStream = new TestClientCharacterStream("localhost", 9498);
testClientCharacterStream.sendData("Hello!!!");
System.out.println("### Terminated");
}
private InetSocketAddress adress;
private Socket clientSocket;
private BufferedWriter out;
public TestClientCharacterStream(String serverIp, int port) {
this.adress = new InetSocketAddress(serverIp, port);
try {
clientSocket = new Socket();
clientSocket.connect(adress, 10000);
this.out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
} catch (IOException e) {
System.err.println("Something went wrong on instantiating a new TestClientCharacterStream");
e.printStackTrace();
}
}
public void sendData(String string) {
try {
out.write(string);
System.out.println("[CLIENT] : Sent new message: " + string);
out.flush();
out.close(); // If I don't close the stream, I'm going to get a "java.net.SocketException: Connection reset" on the server
} catch (IOException e) {
closeStreamAndSocket(clientSocket, out);
e.printStackTrace();
}
}
private void closeStreamAndSocket(Socket socket, BufferedWriter out) {
try {
if (out != null) {
out.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
System.err.println("Cannot close stream or socket.");
e.printStackTrace();
}
}
}
The servers Output:
### Started
[SERVER] : Server started!
[SERVER] : Wait for data on port 9498 ...
Error while accepting connection or reading input!
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/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:270)
at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:313)
at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
at java.base/java.io.InputStreamReader.read(InputStreamReader.java:177)
at java.base/java.io.BufferedReader.fill(BufferedReader.java:162)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:329)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:396)
at TestServerCharacterStream.waitForData(TestServerCharacterStream.java:40)
at TestServerCharacterStream.main(TestServerCharacterStream.java:12)
### Terminated
I want to run a java server program in my ubuntu computer through terminal but the problem is that once I start the program I can not stop it (the program is running in the terminal and waiting for the client).
This is my code:
import java.net.*;
import java.io.*;
public class EchoServer2 extends Thread {
protected Socket clientSocket;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2000);
System.out.println("Connection Socket Created");
try {
while (true) {
System.out.println("Waiting for Connection");
new EchoServer2(serverSocket.accept());
}
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
} catch (IOException e) {
System.err.println("Could not listen on port: 2000.");
System.exit(1);
} finally {
try {
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close port: 2000.");
System.exit(1);
}
}
}
private EchoServer2(Socket clientSoc) {
clientSocket = clientSoc;
start();
}
public void run() {
System.out.println("New Communication Thread Started");
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
} catch (IOException e) {
System.err.println("Problem with Communication Server");
System.exit(1);
}
}
}
I know that I can kill the process but I don't want to stop the program forcefully. I want to know: how can I stop the program safely? How can I implement this in my code?
Let's get it clear, you block the main thread at client acception. It will be no real way to cleanly close the program.
My solution would be to run a separate thread, that will do the acception job.
To illustrate, here's my code:
This is the acception thread:
private static Thread acception = new Thread("Acception Thread") {
public void run() {
try {
while (true) {
System.out.println("Waiting for Connection");
new EchoServer2(serverSocket.accept());
}
-> } catch (SocketException e) {
-> if(serverSocket.isClosed())
-> System.out.println("Connection Closed.");
-> }
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
}
};
Here's the modified main method:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2000);
System.out.println("Connection Socket Created");
-> acception.start();
} catch (IOException e) {
System.err.println("Could not listen on port: 2000.");
System.exit(1);
}
//support to close, using the command line.
Scanner scn = new Scanner(System.in);
String s = scn.next();
while(true) {
if("quit".equals.(s)) {
try {
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close port: 2000.");
System.exit(1);
} finally {
break;
}
}
s = scn.next();
}
}
You can hit the Ctrl + C keys and it will send a SIGINT (interrupt) to your program. If you don't have specific logic to run at the program shutdown it'd probably do the job.
If you have some logic to run at program shutdown, check this answer.
Check this link http://www.oracle.com/technetwork/java/javase/signals-139944.html Should help you
Edit:
Solution 1: Add this to your main method
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Prepare to exit");
//some cleaning up code...
}
});
Solution 2: Add another thread which waits for "exit" command, SOmething like:
new Thread() {
#Override
public void run() {
System.out.println("Type exit to exit;-)");
Console c = System.console();
String msg = c.readLine();
if (msg.equals("exit")) {
//some cleaning up code...
System.exit(0);
}
}
}.start();
A few days ago i tried to create a server - client or client Server as an experiment to learn about socket using a thread but then someone told me that i should use swingWorker. I did some research how to use and have implemented it in as practice but it still doesn't work. the swingWorker thread doesn't look like it is running even tho i get a connection and have used .excute(). If you guys can help spot where i am doing wrong that will be great. SwingWorker class is in the startSever() and startClient() method.
private void startServer() {
SwingWorker <Void, String> runningServer = new SwingWorker<Void, String>(){
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
String incomeMessage =null;
while(connected){
inStream = connection.getInputStream();
inDataStream = new DataInputStream(inStream);
if (myMessage !=null){
outStream = connection.getOutputStream();
outDataStream = new DataOutputStream(outStream);
outDataStream.writeUTF(myMessage);
}
if((incomeMessage = inDataStream.readUTF())!=null){
clientMessage = incomeMessage;
publish(clientMessage);
incomeMessage =null;
}
}
} catch (IOException e) {
clientMessage = "Connection Lost";
}
return null;
}
runningServer.execute();
}
Here's a VERY basic example.
Basically, because you program requires asynchronous communications (that is, you need to be able to read from the socket AND write to it at the same time), you need to offload each stream to a separate thread.
The management process of this example is, well, no existent. Realistically, you should have some kind of "connection" manager that would be able to cleanly close the output and input threads so that, for example, when the user types "bye", the output thread would be able to tell the connection manager that the connection should be terminated. It would then tell the input thread to stop reading any new message and terminate...
Client
public class Client {
public static void main(String[] args) {
try {
Socket master = new Socket("localhost", 8900);
new Thread(new InputHandler(master)).start();
new Thread(new OuputHandler(master)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<server> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.nextLine();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Server
public class Server {
public static void main(String[] args) {
try {
ServerSocket master = new ServerSocket(8900);
Socket socket = master.accept();
new Thread(new InputHandler(socket)).start();
new Thread(new OuputHandler(socket)).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static class InputHandler implements Runnable {
private Socket socket;
public InputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (commune) {
String text = reader.readLine();
System.out.println("\n<client> " + text);
if (text.toLowerCase().equals("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
public static class OuputHandler implements Runnable {
private Socket socket;
public OuputHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean commune = true;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
while (commune) {
System.out.print("> ");
String text = scanner.next();
writer.write(text);
writer.newLine();
writer.flush();
if (text.equalsIgnoreCase("bye")) {
commune = false;
}
}
} catch (Exception exp) {
exp.printStackTrace();
} finally {
try {
writer.close();
} catch (Exception e) {
}
try {
socket.close();
} catch (Exception e) {
}
}
}
}
}
Update (whine)
While I have your source code in front of me...
There should very, very, rarely be a need to do textMessage.addKeyListener(this)
Because you are using a JTextField, you should be using a ActionListener instead. There are a a number of important reasons for this, but for you, the main one would be the fact that a "accept" action is Look and Feel dependent. While most systems do use Enter as there "accept" action, is not a guarantee.
Have a look at How to Write a Action Listener for more information
Given the general complexity of what you are trying to do, +1 for a overall good attempt!
Using this example, the following changes work with a single telnet client.
private PrintWriter out;
...
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
myMessage = friendLabel + textMessage.getText();
if (out != null) {
out.println(myMessage);
}
...
}
...
protected Void doInBackground() {
try {
listeningSocket = new ServerSocket(port);
System.out.println("Waiting for connection");
connection = listeningSocket.accept();
connected = true;
System.out.println("Connected");
Scanner in = new Scanner(connection.getInputStream());
out = new PrintWriter(connection.getOutputStream(), true);
publish("Connected");
while (true) {
publish(in.nextLine());
}
} catch (IOException e) {
clientMessage = "Connection Lost";
try {
connection.close();
System.out.println("Closed");
} catch (IOException e1) {
e1.printStackTrace();
connected = false;
}
}
return null;
}
I see your server port is 8900 and your client port is 8900 too. I am not sure if it matters if the server and client are running on the same machine...
I got to stage where client and server communicate, sending messages from and to each other.
The problem I am having is how to close the connection without causing an error?
If I terminate one of the apps (either server or client) that causes the connection to be lost, and then it causes the loop that is waiting for input to loop indefinitely and showing null's.
I tried closing sockets, buffers and even the thread, didn't work.
This is the client side
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
This is the server side
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(
socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Both use these classes:
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(
this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
//***HERE EXTRA BIT FOR THE SERVER
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
text.setText(msg);
}
}
the only difference is the server has this bit where it says above ***HERE EXTRA BIT FOR THE SERVER
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println("Message recieved");
so basically, client connects, server accepts, then client sends message, servers receives message and shows it, and then sends "Message received" to the client, and the client shows it.
All this works fine, but once the connection is lost, they hang on showing null repeatedly, and I have to force the app to close.
You aren't checking for end of stream. If readLine() returns null, the peer has closed the connection, and you must do likewise and stop reading.
It's hard to believe you really need a new thread for every line to update the UI.
I have seen a similar problem as mine but I still wasn't able to resolve this.I am trying to do a relay chat. I've done all the flushing. I even tried autoflush(with println). But after the first message I sent to server, succeeding messages aren't sent anymore. I am not closing the printwriter. I checked the socket and yes, it's still connected, I printed the message to be sent, nothing seems to be wrong. Help would be very much appreciated.
here is a part of the client code:
public void initializeConnection(){
try {
host = InetAddress.getLocalHost();
clientSocket = new Socket(host.getHostAddress(), port);
outToServer = new PrintWriter(clientSocket.getOutputStream(),true);
String message = outMsgArea.getText()+"Hello";
outToServer.println(message);
System.out.println(clientSocket.isConnected());
}
catch(IOException ioEx) {
ioEx.printStackTrace();
}
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==quit){
try {
outToServer.close();
clientSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
else if(e.getSource()==button){
if(outMsgArea.getText()!=null || !outMsgArea.getText().equals("")){
/*try {
outToServer = new PrintWriter(clientSocket.getOutputStream(), true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}*/
String message = outMsgArea.getText()+"Hello";
System.out.println(clientSocket.isConnected());
outToServer.println(message);
outToServer.flush();
//outToServer.println(message);
outMsgArea.setText("");
}
}
}
server:
while(true) {
try {
Socket connectionSocket = servSocket.accept();
Scanner inFromClient = new Scanner(connectionSocket.getInputStream());
String clientSentence = inFromClient.nextLine();
System.out.println(clientSentence);
}
catch(IOException ioEx) {
ioEx.printStackTrace();
}
}
}
I don't think
Socket connectionSocket = servSocket.accept();
Scanner inFromClient = new Scanner(connectionSocket.getInputStream());
should be inside the while loop.