How to write java TCP object transmission for multiple clients - java

I'm writing a primitive Graphical MUD-like online game using only the Java standard library - just Swing and TCP sockets (for school and for fun). The game has a server (a spare laptop in my closet) that accepts TCP connections from players and takes in objects (using ObjectInputStream) - chat strings and dropped items and such - and uses those objects to make changes to the virtual world that are then forwarded to the other players.
Initially, I thought I could make each and every player connect to the same TCP port on my server (port 5010) by having my server's main thread listen for each of their connections using a loop, like so...
while (true)
{
//get new connection
serversocket = new ServerSocket(5010);
socket = serversocket.accept();
serversocket.close();
//proceed to log in player using their computer's host name.
}
Then I pass each new player's TCP socket connection to a thread dedicated to that player's object input and output, like so:
new_thread = new Thread(new Server_Input_Thread(main_thread_socket));
When I'm debugging, I test the game by running both the server side application and the client side application from my other laptop and connect through "localhost".
But I'm having problems. I can't get past IOExceptions such as Bind exceptions and "java.net.SocketException: socket closed" when listening for a new connection (on port 5010) after the initial connection (also on port 5010) has been made.
Apparently the way I'm doing it isn't working and perhaps I'll need to assign each player a unique port number rather than have every player try to connect to port 5010, or maybe it's because I'm using my coding laptop as both a client and a server.
Unfortunately for me, I have no idea what I'm doing - I just declared Computer Science as my major one semester ago. Please explain how to structure the network connections for such a virtual world and avoid the IOExceptions that occur immediately after the initial connection between the client application and the server, as the server is starting to once again listen for a new connection on port 5010 on the main thread.

Try this
serversocket = new ServerSocket(5010);
while (true)
{
socket = serversocket.accept();
//proceed to log in player using their computer's host name.
}
serversocket.close();
I am not going to show you the other problems you are going to face but this should at least get you going.

Related

Is it a good practice to keep a Socket connection open for reading?

I am trying to build an Android IM, since users may have new messages from others, should I keeps the TCP connection open and keep reading data from it? e.g.
while(!shutdown) {
int count = socketChannel.read(buffer);
// do something with buffer
}
This depends on your implementation. If you're using blocked sockets then you wouldn't want to do this. It would mean that if you have more than one client connecting to the server they would block all other clients from connecting to that server socket.
What you could do is have a server socket running consistently (as you normally would) and then to connect to it with a client socket to check and receive any new messages that have arrived. Once you've received your message you can close the socket. This could be performed every n seconds.
The other option is to use non-blocked socket connections and always keep them open but this could lead to issues if you have many clients.

Will I need a separate socket and thread for every player that joins? [JAVA]

I have been learning about sockets for sometime now (I'm quite young) and I think I have a good grip on java sockets. I have decided to create a simple multiplayer Java 2D social game. My goal is to have the server output players' X,Y coordinates and chat every 10 milliseconds. From what I have read, my very average logic tells me that only one user at a time can connect to a socket. So therefore I will need a separate thread and socket for each player that connects.
Is it necessary to have one ServerSocket and thread per player?
You should have just one ServerSocket listening on a port that is known to the client. When a client connects to the server, a new Socket object is created and the original ServerSocket goes back to listening again. You should then spin off a new Thread or hand over to an Executor the actual work of talking to the client, otherwise your server will stop listening for client connections.
Here is a very basic sketch of the code you will need.
import java.net.*;
import java.util.concurrent.*;
public class CoordinateServer {
public static void main(String... argv) throws Exception {
// 'port' is known to the server and the client
int port = Integer.valueOf(argv[0]);
ServerSocket ss = new ServerSocket(port);
// You should decide what the best type of service is here
ExecutorService es = Executors.newCachedThreadPool ();
// How will you decide to shut the server down?
while (true) {
// Blocks until a client connects, returns the new socket
// to use to talk to the client
Socket s = ss.accept ();
// CoordinateOutputter is a class that implements Runnable
// and sends co-ordinates to a given socket; it's also
// responsible for cleaning up the socket and any other
// resources when the client leaves
es.submit(new CoordinateOutputter(s));
}
}
}
I have put sockets here since they are easier to get started with, but once you have this working well and want to boost your performance you will probably want to investigate the java.nio.channels package. There's a good tutorial over at IBM.
Yes.
A Socket is connection between two points (the client and the sever). This means that each player would require their own socket connection on the server end.
If you want your application to be responsive in any meaningful manner, then each incoming connection on the server should be processed within their own thread.
This allows clients that might have a slow connection not to become a bottle neck for others. It also means that if a client connection is lost, you don't burden any updates waiting for time-outs.

How a threaded server continues to listen on the post for more incoming connections?

I am going through Sun's Java tutorial. I am in the lesson about sockets. There is the following code for a simple threaded server:
import java.net.*;
import java.io.*;
public class KKMultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
The server is said to "keep listening for more incoming connections". I just don't understand how it's possible; the line serverSocket.accept() constructs a new (client) Socket object which is, according to the tutorial "bound to the same local port and has its...". Well, how is it possible that the server is communicating with the client and listening to more incoming connections on the same port? As far as I know, if a port is used for some connection it is blocked and cannot be used for more things.
So what am I getting wrong here?
Well, a socket is not one-to-one based on a port, it is unique on a tuple of (address, port). A connection - the pair of the local and remote sockets involved in the communication - is used to demux incoming data from a port to the correct socket, allowing multiple sockets on one port. See Wikipedia. In other words, the relationship of sockets to ports are N-to-1
getting multiple connections on the same port is entirely possible as each TCP connection is a (local host, local port, remote host, remote port) tuple as long as at least 1 is different the connections are distinct and won't interfere (besides bandwidth drops)
clients attempting to connect to a server generally get a port assigned from the OS that is not used currently
Listening sockets work like a receptionist in on a business's phone switch. Everyone calls the switch number, and the receptionist responds to each incoming call on the switch line by having someone else handle the call on another line. Even though the receptionist can only take one call at a time, the switch line is tied up only very briefly because it is used only to establish a connection.
[...]TCP demultiplexes incoming segments using all four values that comprise the local and foreign addresses: destination IP address, destination port number, source IP address, and source port number. TCP cannot determine which process gets an incoming segment by looking at the destination port only. Also, the only one of the [various] endpoints at [a given port number] that will receive incoming connection requests is the one in the listen state. (p255, TCP-IP Illustrated Volume 1, W. Richard Stevens)
The last sentence in the above quote is the key to understanding.
Interestingly, a socket isn't really identified by the combination of IP address and port. This is unique only in context, where the context is either a particular connection or the listening state. Only one listener socket can bind to a particular IP/port combination.
The short and sweet answer is that the port is blocked for OTHER programs and processes. Only the program that opened the port can now listen on it. BUT it can listen to many different clients on the same port.
When a client connects, it creates a unique socket. A socket is comprised of the listening IP address and port (the one you opened) AND the calling IP address and port. Because the caller's IP address and port are always unique, each socket is unique and identifiable to your listener.
Even if I connected to your program twice from the same machine, my machine would select a new and random source port for each connection -- thus ensuring that we have a unique socket each time.
Based on this link
The accept method waits until a client starts up and requests a connection on the host and port of this server (in this example, the server is running on the hypothetical machine taranis on port 4444). When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has its remote address and remote port set to that of the client.The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket This particular version of the program doesn't listen for more client connection requests.
Here is SO discussion which may clear confusion about how single port handles multiple client calls Port and Socket SO discussion .
To put it in simple terms, most of the webservers listen on port 8080 and multiple clients will access same port to access your website.

What will happen to a TCP/UDP serversocket when I switch wifi network?

what will happen to the serversocket in my app when I suddenly change the wifi network? I guess it will shut down since my device will get a new IP, at least in TCP, is the UDP MulticastSocket prone to this as well? And how to end the previous Server socket thread and start a new one when the network changes? One solution is using time outs, another is using a flag that will indicate whether the infinite loop should end or not but since listening to a socket is a blocking function it will produce an exception/error anyways.
Any thoughts will be appreciated! :)
EDIT: sample of my server thread.
ServerSocket ss = new ServerSocket(4445);
while(true){
Socket socket = ss.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object obj = in.readObject();
Log.i("TAG", "Received: " + obj.toString());
in.close();
socket.close();
}
TCPIP connection will break. So client would have to connect again.
UDP will be ok provided your IP does not change after reconnection. Of course if you transmit UDP its not going to make a difference for that machine.
You should get an exception in case of TCPIP which you can handle.
UDP sockets that are not bound to the address will remain open, as they are stateless. TCP listening sockets not bound to the address will remain open as well.
Conntected TCP sockets may be severed (RST) or just linger until a timeout hits.
It is a little known fact that IP mandates it that a device by default will accept packets directed to any address it has configured on any interface, no matter on which interface the packet arrives. If this were not so, routing would be broken. One can use packet filters to filter out packets with non-matching addresses depending on the interface.

Why do sockets not die when server dies? Why does a socket die when server is alive?

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.

Categories

Resources