I'm programming a client server app. I'm wondering to end the connection, which side should decide to end it, client or server?
Then if for example the client did it, should the server still keep open or not?
Suppose we have the below codes for each client and server:
socket = new Socket("127.0.0.1",3000);
........
socket.close();
or
serverSocket = new ServerSocket(3000);
socket = serverSocket.accept();
......
serverSocket.close();
EDIT:
according to the matt's answer, i pot my code here and let see why my code doesnt work:
generally, i have a Jframe program as client which will connect to a server and while its open, i want the connection being alive, since it send info to the server and server should response for the result. but if i dont use closing the socket from server it gives an error and if i use, after once calculation, it closes the connection:
Server
private static PrintWriter toClient;
private static BufferedReader fromClient;
public static void run() throws IOException, SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException, SAXException, XPathExpressionException
{
System.out.println("Server is waiting for connections...");
while(true)
{
openStreams();
processClient();
closeStreams();
}
}
OpenStream:
public static void openStreams() throws IOException, SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException, SAXException, XPathExpressionException
{
serverSocket = new ServerSocket(3000);
socket = serverSocket.accept();
System.out.println("Connected");
toClient = new PrintWriter(socket.getOutputStream(),true);
fromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Closestearms:
public static void closeStreams() throws IOException
{
fromClient.close();
toClient.close();
socket.close();
serverSocket.close();
System.out.println("Disconnected");
}
the error i receive if i remove the closestream();
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:359)
at java.net.ServerSocket.bind(ServerSocket.java:319)
at java.net.ServerSocket.<init>(ServerSocket.java:185)
at java.net.ServerSocket.<init>(ServerSocket.java:97)
Depends on your application's logic. Both are valid, and you must make sure your code is correct in both cases, since if the connection is broken "involuntarily" (like a network drop), it will appear to both sides as if the other side had closed the connection.
So your code must handle both cases gracefully.
Your closing code is suspicious: you're closing the listening socket, which is unusual. You should only close the listening socket when you don't want any more incoming connections (i.e. usually for a server, when you're shutting down the server).
Only close the socket you got from accept to end that "conversation", and don't re-open the server listening socket. (The exception you're getting might be an "Address already in use" in this case. See How to set reuse address option for a datagram socket in java code? for an example of how to avoid that specific problem.)
Either end may close the connection - neither is "more correct".
However, it is important to clear up one (seeming) misunderstanding in your code:
closing the ServerSocket is not closing the socket that represents the connection between the two end points.
The ServerSocket is a listening socket on a port. When a client makes a connection to the ServerSocket on that port, a (normal) Socket is returned by the ServerSocket.accept() method. Communication between your two end points uses the input and output streams associated with this (normal) Socket.
Closing the ServerSocket just stops listening on the well known port and doesn't relate to the established sockets.
The socket is present in both the client and server program. Closing any socket will throw exception on the other side.
Related
I have a simple server that looks like this
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(4999);
Socket s = ss.accept();
InputStream is = s.getInputStream();
while (true) {
System.out.println(is.read());
}
}
It accepts a single client socket, reads from it forever and prints out the number that was sent from the client socket.
I have a client like this
public static void main(String[] args) throws IOException, InterruptedException {
int id = Integer.valueOf(args[0]);
Socket s = new Socket("localhost", 4999);
OutputStream os = s.getOutputStream();
while (true) {
os.write(id);
Thread.sleep(1000L);
System.out.println("Sent");
}
}
It connects to the server and sends the number it received as command-line argument forever.
I start the server.
I start a client like java -jar client.jar 123.
Then I start another client like java -jar client.jar 234.
No errors happen on neither the server side nor the client side.
Each client prints the Sent message every 1 second, neither gets blocked.
The server only prints 123 until the end of times.
My questions:
What happens with the bytes written by the second client?
I would expect the second client to receive an error or get blocked or something, but nothing happens. Why?
Note: I know that this code is bad and I should handle clients in threads and call ServerSocket.accept() and all that jazz.
Update:
Based on the accepted answer the solution is to create the server like new ServerSocket(4999, 1); where 1 is the size of the backlog. 0 would mean to use whatever the default setting is configured in Java.
By using 1 there can be only one connection in a "non-accepted" state. Anymore client trying to connect gets a connection refused!
The bytes written by the second client will go into the client Socket's send buffer, since you're writing to a socket that doesn't have an established connection yet. Eventually the send buffer will fill up. You could try playing with Socket.setSendBufferSize() to see what happens when it fills up.
A ServerSocket has a listen backlog for connections that haven't been accepted yet. The second client's connection is in the backlog, and if the server would ever get around to accepting it (which it won't, with your code, but there is no way for the client to know that), it would be established and the client's send buffer would be sent merrily along. You could try calling the constructor ServerSocket(int port, int backlog) with a backlog of 1 to see what happens to the client when the listen backlog fills up - it should get connection refused.
This is my code when I run it in debug mode in eclipse it shows me that it doesn´t continue it stops a stays in the code where I have put an arrow.
private ServerSocket serverSocket = null;
private Socket socket= null;
private ObjectInputStream inputStream= null;
public void ConnectTCP(){
try{
serverSocket = new ServerSocket(5000);
---->socket = serverSocket.accept();
inputStream = new ObjectInputStream(socket.getInputStream());
System.out.print("Server is Running");
}catch(IOException e){
e.printStackTrace();
}
}
Your socket is already created at this line. Because server binds to a port, at the moment ServerSocket constructor is called. As for accept method, due to JavaDoc it
Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
A new Socket s is created and, if there is a security manager, the security manager's checkAccept method is called with s.getInetAddress().getHostAddress() and s.getPort() as its arguments to ensure the operation is allowed. This could result in a SecurityException.
So, accept method is just waiting for client connections, that is the reason, why execution stops at this point. May be, it could be helpfull to read a java official tutorial for writing a server side.
Actually it won't stop, it waiting for connection.
When a client want to connect it then it connect with that socket and program flow goes next line.
I created a simple echo server in Java. When I try it locally, it works as it should. However, when I try to connect it from a different computer using the IP address and the port number the server is running on, it never connects. Is there anything else that should be done to connect to a server from a different computer?
import java.net.Socket;
import java.net.ServerSocket;
public class EchoServer {
public static void main(String[] args) throws Exception {
// create socket
int port = 4444;
ServerSocket serverSocket = new ServerSocket(port);
System.err.println("Started server on port " + port);
// repeatedly wait for connections, and process
while (true) {
// a "blocking" call which waits until a connection is requested
Socket clientSocket = serverSocket.accept();
System.err.println("Accepted connection from client");
// open up IO streams
In in = new In (clientSocket);
Out out = new Out(clientSocket);
// waits for data and reads it in until connection dies
// readLine() blocks until the server receives a new line from client
String s;
while ((s = in.readLine()) != null) {
out.println(s);
}
// close IO streams, then socket
System.err.println("Closing connection with client");
out.close();
in.close();
clientSocket.close();
}
}
}
Please check the following things.
Is the server computer behind a network proxy ?
Does it have an independent public IP Address by which it is accessible from
anywhere ? Or, does it have an internal IP, by which it can be accessed in your LAN ?
Make sure FireWalls has an exception for port 4444. Or you may turn it of in both client and server.
If it does not help, post the exception you are getting (by editing the question). Or the server program is just freezing without any error ?
If this is on your LAN refer to the machine running your EchoServer by name (the actual machine name, I believe they show you to do it this way on the Sun Tutorial that posted this echo server excercise correct?). If that works it would help a lot in troubleshooting the issue.
I create a new thread that runs the following code:
public static void startServer() throws IOException {
serverSocket = new ServerSocket(55000);
Socket clientSocket = serverSocket.accept();
}
The above code is run in a thread. Now, in my main class, I successfully create a socket
connection to the server and I have checked it's integrity which is fine. here is the code:
Socket testServerSocket = new Socket("127.0.0.1", 55000);
assertEquals("/127.0.0.1", testServerSocket.getInetAddress().toString());
assertEquals(55000, testServerSocket.getPort());
This runs perfect. Then, again from my main, I kill the server connection that closes the connection on the server side. However the following code keeps failing:
assertEquals(false, testServerSocket.isBound());
It keeps returning true. Likewise, if I check the remote IP address for the connection, it doesn't return null, but rather '/127.0.0.1'. Any ideas why this might be happening? Many thanks for your help
I'm not an expert on sockets (I know what they are, but haven't ever used sockets on Java, only with C on Linux), but like JavaDoc for java.net.Socket states, 'A socket is an endpoint for communication between two machines'. So while closing server-side socket does destroy the connection between the two sockets (server- and client-side), your client-side socket is still bound, hence the isBound() is returning true. Maybe you meant to call isConnected() or isClosed()?
I try to play with sockets a bit. For that I wrote very simple "client" and "server" applications.
Client:
import java.net.*;
public class client {
public static void main(String[] args) throws Exception {
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("before");
Socket clientSideSocket = null;
try {
clientSideSocket = new Socket(localhost,12345,localhost,54321);
} catch (ConnectException e) {
System.out.println("Connection Refused");
}
System.out.println("after");
if (clientSideSocket != null) {
clientSideSocket.close();
}
}
}
Server:
import java.net.*;
public class server {
public static void main(String[] args) throws Exception {
ServerSocket listener = new ServerSocket(12345);
while (true) {
Socket serverSideSocket = listener.accept();
System.out.println("A client-request is accepted.");
}
}
}
And I found a behavior that I cannot explain:
I start a server, than I start a client. Connection is successfully established (client stops running and server is running). Then I close the server and start it again in a second. After that I start a client and it writes "Connection Refused". It seems to me that the server "remember" the old connection and does not want to open the second connection twice. But I do not understand how it is possible. Because I killed the previous server and started a new one!
I do not start the server immediately after the previous one was killed (I wait like 20 seconds). In this case the server "forget" the socket from the previous server and accepts the request from the client.
I start the server and then I start the client. Connection is established (server writes: "A client-request is accepted"). Then I wait a minute and start the client again. And server (which was running the whole time) accept the request again! Why? The server should not accept the request from the same client-IP and client-port but it does!
When you close the server , the OS will keep the socket alive for a while so it can tell the client the connection has been closed. This involves timeouts and retransmissions which can take some time. You might find some info here and here. If you want your server to be able to immediately rebind the same socket, call setReuseAddress(true) on it, though it might be the client sockets that's in a TIME_WAIT state.
The socket is no longer in TIME_WAIT state, and can be reused again by any program.
Your client code just connects, closes the socket and then exits. As far as the server/OS tcp stack is concerned, these are different connections - it's fine to reuse the source port as long as any prior connection have been torn down. (Note that the OS might not tear down all of the housekeeping of the connection immediately after you call .close() or your program exits, there's some time delay involved so it can be sure all packets have been sent/received)
It is likely the operating system has not yet shutdown the sockets, try the netstat command (should work on Windows or Unix/Linux). If you run it immediately after you close client or server you should still the socket in "TIME_WAIT" "CLOSE_WAIT" or something similar. You wont be able to reuse those ports until they are fully closed.
Per Question #3: Many clients can connect to a server attached to a single port. Apache runs on port 80 but that doesn't mean only one person can view your website at a time. Also you are closing your client socket before you're opening a new one.