I am making a prototype client & server so that I can understand how to handle reconnects.
The server ought to create a serversocket and listen forever. A client may connect, send its data, and close its socket but it will not send a "I'm done and closing" type message to the server. For this reason, the server gets a EOFException when it does a readByte() since the remote client has closed. In the error handler for the EOFException, it will close the socket and open a new one.
Here's the problem: The client sometimes gets a SocketWriteError when it does the outputStream.write() call even after it successfully opens the socket/inputstream/outpustream. It may have something to do with the frequency that I'm opening and closing these sockets. One interesting thing is that the client does an arbitrary number of writes/close/reconnects before crapping out. It will sometimes crap out on the first reconnect, other times it will take 50 reconnects before seeing the SocketWriteError.
Here's the error on the client side:
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:115)
at bytebuffertest.Client.main(Client.java:37)
Here are some snippets of code:
SERVER:
public static void main(String[] args)
{
Server x = new Server();
x.initialize();
}
private void initialize()
{
ServerSocket s;
InputStream is;
DataInputStream dis;
while (true) //ADDED THIS!!!!!!!!!!!!!!!!!!!!!!
{
try
{
s = new ServerSocket(4448);
s.setSoTimeout(0);
s.setReuseAddress(true);
is = s.accept().getInputStream();
System.out.println("accepted client");
dis = new DataInputStream(is);
try
{
byte input = dis.readByte();
System.out.println("read: " + input);
} catch (Exception ex)
{
System.out.println("Exception");
dis.close();
is.close();
s.close();
}
} catch (IOException ex)
{
System.out.println("ioexception");
}
}
}
CLIENT:
public static void main(String[] args)
{
Socket s;
OutputStream os;
try
{
s = new Socket("localhost", 4448);
s.setKeepAlive(true);
s.setReuseAddress(true);
os = s.getOutputStream();
int counter = 0;
while (true)
{
try
{
os.write((byte) counter++);
os.flush();
os.close();
s.close();
s = new Socket("localhost", 4448);
s.setKeepAlive(true);
s.setReuseAddress(true);
os = s.getOutputStream();
} catch (Exception e)
{
e.printStackTrace();
System.err.println("ERROR: reconnecting...");
}
}
} catch (Exception ex)
{
ex.printStackTrace();
System.err.println("ERROR: could not connect");
}
}
Does anyone know how to properly reconnect?
Don't close the ServerSocket on an error, just .accept() a new connection.
What I normally do is each time ServerSocket.accept() returns a Socket, I spawn off a thread to handle sending and receiving from that Socket. That way you're ready to start accepting a new connection as soon as somebody wants to connect to you.
Related
I have created a server-client project where the server keeps listening and prints the information. However, when i shutdown the client, the server remains open. The problem is that I need to insert this into another application, and, if the server does not close at first, the application will not open unless i kill the process in that port (but this is not an option to me). What should I do to properly close the server once the client disconnects?
Here is the code:
Server:
public class Server {
public static void main(String[] args) {
Connection conn = new Connection();
new Thread(conn).start();
}
private static class Connection implements Runnable {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(5005)) {
Socket socket = serverSocket.accept();
listener(socket);
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void listener(Socket socket) throws IOException {
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
boolean alive = true;
while (alive) {
try {
outputStream.writeUTF(new Scanner(System.in).nextLine());
System.out.println(inputStream.readUTF());
} catch (IOException ex) {
ex.printStackTrace();
alive = false;
}
}
}
}
}
Client:
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 5005)) {
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
while (socket.isConnected()) {
System.out.println("Incoming data: " + inputStream.readUTF());
outputStream.writeUTF(new Scanner(System.in).nextLine());
outputStream.flush();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Since now, thank you very much!
The thing that force the system wait and not close is this line at your Server.java :
outputStream.writeUTF(new Scanner(System.in).nextLine());
Once it starts waiting the user input, it waits forever along the life time of the instance although your client is disconnected.
So what you can do ? You can create another thread that makes periodic "ENTER" inputs (if you insist using new Scanner(System.in)) for example input per 5 seconds. After the enter, or any other meaningful input, if you decide this is not from your client, don't write it to the client and wait user input again (if your client still connected !). If your client is not connected, just finish your loop.
Please check Java Robot class and this example
How to restart ServerSocket after IOException?
My server socket sometimes gets an EOFException and then stops accepting new connections. To solve this I have tried closing the old server socket and creating a new one after the exception is thrown. However even after the new server socket is created, new connections are not accepted. Can some one see why this does not work?
public Server() throws IOException {
try {
listen(port);
}
catch (IOException e) {
System.out.println("Server() - IO exception");
System.out.println(e);
/*when an exception is caught I close the server socket and try opening it a new one */
serverSocket.close();
listen(port);
}
}
private void listen(int port) throws IOException {
serverIsListening = true;
serverSocket = new ServerSocket(port);
System.out.println("<Listening> Port: " + serverSocket);
while (serverIsListening) {
if (eofExceptionThrown){ //manually triggering an exception to troubleshoot
serverIsListening = false;
throw new EOFException();
}
//accept the next incoming connection
Socket socket = serverSocket.accept();
System.out.println("[New Conn] " + socket);
ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream());
// Save the streams
socketToOutputStreams.put(socket, oOut);
// Create a new thread for this connection, and put it in the hash table
socketToServerThread.put(socket, new ServerThread(this, socket));
}
}
2x entry point , one form catch: never ends well.
try {
listen(port);
}
catch (IOException e) {
System.out.println("Server() - IO exception");
System.out.println(e);
/*when an exception is caught I close the server socket and try opening it a new one */
serverSocket.close();
listen(port);
}
I would do in a loop, while a boolean is true:
while(needToListen){
try{
listen(port)
}catch(Exception ex){
if(exception is what needed to break the loop, like a message has a string on it){
break;
}
}
}
if(needToListen){
Log.e("something unexpected, unrecoverable....");
}
My server socket sometimes gets an EOFException and then stops accepting new connections
No it doesn't. ServerSockets never get EOFExceptions. Rather, one of your accepted Sockets is getting an EOFException, which is only to be expected, and you are closing both that Socket, which is correct, and the ServerSocket, which is incorrect. Exceptions on accepted sockets don't affect the listening socket.
I have a program running on a server (Server A) which listens on one port for an external connection (from an external server, B), then listens on another port for an internal connection on the same server (Server A). It then passes data from the internal to external connection and back again.
I want to know if there is a way I can detect that the client external was disconnected. I just need one external connection at a time, but I would like to be able to accept a new one if the external client reboots or something like that.
This socket level stuff is all fairly new to me, so if there is a better way of going about this, I'm all ears. The one stipulation is that the client running on Server B must be the one to initiate the connection and the connection must live for as long as possible.
public void handleConnection() {
System.out.println("Waiting for client message...");
try {
SSLSocket extSocket = (SSLSocket) this.externalServerSocket.accept();
ObjectInputStream externalOis = new ObjectInputStream(extSocket.getInputStream());
ObjectOutputStream externalOos = new ObjectOutputStream(extSocket.getOutputStream());
System.out.println("Client connection establisthed");
// Loop here to accept all internal connections
while (true) {
SSLSocket internalSocket = (SSLSocket) this.internalServerSocket.accept();
new ConnectionHandler(externalOis, externalOos, internalSocket);
}
} catch (IOException e) {
System.err.println(e.getMessage());
return;
}
}
class ConnectionHandler implements Runnable {
private SSLSocket internalSocket;
private ObjectOutputStream internalOos;
private ObjectInputStream internalOis;
private ObjectInputStream externalOis;
private ObjectOutputStream externalOos;
public ConnectionHandler(ObjectInputStream externalOis,
ObjectOutputStream externalOos, SSLSocket internalSocket) {
this.internalSocket = internalSocket;
try {
this.internalOis = new ObjectInputStream(this.internalSocket.getInputStream());
this.internalOos = new ObjectOutputStream(this.internalSocket.getOutputStream());
this.externalOis = externalOis;
this.externalOos = externalOos;
} catch (IOException e) {
System.err.println(e.getMessage());
}
new Thread(this).start();
}
#Override
public void run() {
try
{
// process data
Object o = internalOis.readObject();
externalOos.writeObject(o);
Object o2 = externalOis.readObject();
internalOos.writeObject(02);
internalOos.close();
internalOis.close();
this.internalSocket.close();
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (ClassNotFoundException e) {
System.err.println(e.getMessage());
}
}
}
If the client disconnects, readObject() will throw EOFException, and write() will throw an IOException: connection reset. That's all you need.
So I wrote a simple Socket program that send message from Client to Server program and wanted to know what is the proper procedure to go about testing this? Both my Client and Server machines are running on Ubuntu 12.04 and I'm remote connecting to both of them.
For my Client code when I instantiate the client socket (testSocket) do I use its IP Address and Port number or Servers IP Address and Port number?
Here is the Code for Client:
public static void main(String[] args) throws UnknownHostException, IOException
{
Socket testSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
try
{
testSocket = new Socket("192.168.0.104", 5932);
os = new DataOutputStream(testSocket.getOutputStream());
is = new DataInputStream(testSocket.getInputStream());
}
catch (UnknownHostException e)
{
System.err.println("Couldn't find Host");
}
catch (IOException e)
{
System.err.println("Couldn't get I/O connection");
}
if (testSocket != null && os != null && is != null)
{
try
{
os.writeBytes("Hello Server!\n");
os.close();
is.close();
testSocket.close();
}
catch (UnknownHostException e)
{
System.err.println("Host not found");
}
catch (IOException e)
{
System.err.println("I/O Error");
}
}
}
Here is the code for Server:
public static void main(String[] args)
{
String line = new String() ;
try
{
ServerSocket echoServer = new ServerSocket(5932);
Socket clientSocket = echoServer.accept();
DataInputStream is = new DataInputStream(clientSocket.getInputStream());
PrintStream os = new PrintStream(clientSocket.getOutputStream());
while (true)
{
line = is.readLine();
os.println(line);
}
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
I'm new to Sockets and not sure what I'm supposed be seeing. I compiled both programs in terminal fine but not sure which one should I be running first or do they need to be started simultaneously?
Thanks
Your server is running in a infinite loop. Avoid that.
You have to restart your computer.
while (true)
{
line = is.readLine();
os.println(line);
}
try
while (!line.equals("Hello Server!"))
{
line = is.readLine();
os.println(line);
}
Run the server first. echoServer.accept(); waits for a connection. When it gets the first connection,
http://docs.oracle.com/javase/tutorial/networking/sockets/ this is a short java tutorial on how to work with sockets and also you can learn how to make a server that would accept multiple connections at a time. This tutorial explains you always need to start the server first, which is only logical. You should use threads to manage connections and then close them so that you use resources efficiently
I am trying to write a client-server system using Sockets in java, however I cannot seem to read data sent from the server to the client.
Here is the code for the client:
public class ClientSocket
{
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
// establish a connection to All Care's server application through socket 4444 (adjust localhost to reflect the IP address that the server
// is being run from)
public ClientSocket()
{
try
{
clientSocket = new Socket("localhost", 4445);
out = new PrintWriter(clientSocket.getOutputStream());
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
catch (IOException e)
{
System.out.println("Could not connect to All Care Server Application");
}
}
public void closeClientSocket()
{
try
{
clientSocket.close();
}
catch (IOException e)
{
System.out.println("Could not close connection to All Care Server Application");
}
}
public String getMessageFromServer()
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from server");
}
return "No Data";
}
public void sendMessageToServer(String message)
{
out.write(message);
}
}
And here is the Server code:
public class ArFileServer {
public static void main(String[] args)
{
ServerSocket serverSocket = null;
boolean listening = true;
try
{
serverSocket = new ServerSocket(4445);
// infinite loop to continually listen for connection requests made by clients
while (listening)
{
new ClientConnection(serverSocket.accept()).start();
if (serverSocket != null)
{
System.out.println("Connection to client established");
}
}
serverSocket.close();
}
catch (IOException e)
{
System.out.println("Error could not create socket connection to port");
}
}
}
public class ClientConnection extends Thread
{
private Socket socket = null;
public ClientConnection(Socket socket)
{
super("ClientConnection");
this.socket = socket;
}
// the thread that runs after a connection to the server has been accepted
#Override
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sendMessagetoClient(out, "CONNECTION SUCCESS");
// check login credentials sent from client to the server
// if valid send back their encrypted password, otherwise output a login error message
// wait for user input and then do various processes based on their requests
in.close();
out.close();
socket.close();
}
catch (IOException e)
{
System.out.println("Client socket connection error");
}
}
// sends a message to the client
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
}
// listens for a message from the client
String getMessageFromClient(BufferedReader in)
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from client");
}
return "No Data";
}
And here is the line of code im using to see if the data is being sent.
System.out.println(clientSocket.getMessageFromServer());
In your sendMessageToClient() method, you need to flush:
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
out.flush();
}
Or, when you create the PrintWriter, use the constructor with autoflush:
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
And when you write, instead of out.write(message) use printf() or println().
There are several problems here.
You are reading lines but you aren't writing lines.
You aren't checking the result of readLine() for null, which means the peer has closed the connection, which means you must do likewise.
You aren't flushing the PrintWriter after you write.
You are closing things in the wrong order. You must close the output writer/stream you have attached to the socket. Doing that flushes it and then closes the input stream/reader and the socket. Doing this in the wrong order loses the flush. Once you've closed the output you don't need the other two closes.
You are using PrintWriter, which swallows exceptions, across a network, where you need to know about exceptions and errors in communication, and you aren't checking for errors either. Use a BufferedWriter.
in the clint code you are not connecting with server socket.
for clint socket connection
socket soc= new socket ("server host ip",port);