Written by Sean R. Owens (sean at guild dot net). Share and enjoy.
http://darksleep.com/player
These are simple examples of how to use sockets in Java. These examples do NOT cover socket channels, non blocking I/O, or inter thread communication and synchronization.
This example assumes basic familiarity with Java, especially with how to compile and run programs. If you need help compiling and running these, don't ask me. Go somewhere else. (I suggest IRC channel #java on irc.freenode.org - they just love simple questions like those.)
1.0 A Very Simple Example
We start with a very simple client program. All it does is open a socket to a destination address (note that the address is hard coded in the 'main' method as localost:54321), and send the string "Hello World" to the other side 100 times. Each time it sends the string, the other side sends it back, so VerySimpleClient also reads from the socket, and if it doesn't receive the same number of bytes back, it prints an error message. When its done it closes the socket and exits. (Note that technically we don't
need
to close the socket, since when a program exits it closes all sockets and files, but it is a good idea to make a habit of closing your sockets and files when you are done with them.)
Our second program (really, we'll need both of them to test them) is a very simple server program. In fact it is so simple it is almost useless, except as example code. The VerySimpleServer creates a ServerSocket and calls ServerSocket.accept() to wait for a new connection. When some other program tries to open a socket connection to the VerySimpleServer, ServerSocket.accept() creates a
new
socket (this time of class Socket) for the connection. VerySimpleServer then reads data from the connection socket and writes it back to the connection socket until the other program closes the connection socket.
(Note, TCP is a 'stream' based protocol. This means that when you write data to the socket several times in a row, the data will be all stuck together, with out any kind of notion of separation between writes. Because of the way these two programs are interacting it is highly likely that each 'read' by VerySimpleServer will get all of the data sent by each 'write' by VerySimpleClient, but this will not always be the case. In a more advanced program it is the responsibility of the application programmer, i.e. you to write code to separate each message sent by the other program.)
2.0 A Simple Example
This is a slightly more complex example than the very simple example. We will be reusing the VerySimpleClient from the example above. One question you might have asked yourself when you looked at the above example was, "How can VerySimpleServer handle more than one connection at the same time?" Unfortunately the answer is, "Very poorly."
Really the answer is "Not at all.". But, if you were to run a second VerySimpleClient while the first one was still connected, when the second VerySimpleClient tried to connect to the VerySimpleServer, it's connection request would be put on a queue by the OS, waiting for the VerySimpleServer to accept it. When the VerySimpleServer finished with the first client and closed that socket, it would then accept the connection from the second client and process the second clients messages. The second client will wait (possibly forever) until VerySimpleServer is done with the first client.
The second connection can't be handled simultaneously because the program is busy with either reading from (or blocked, waiting to read from) the first connection or writing to (or blocked, waiting to write to) the first connection. There are several ways to solve this problem.
One way, generally considered to be more efficient, but also more complicated, is to use something called "Non Blocking I/O". Non Blocking I/O (part of the java.nio, 'New I/O', API), was not originally included in java, but has been made available as of j2sdk1.4. I'm not going to go into that just yet though.)
Another way to solve this problem is through the use of 'threads'. Basically we're going to use one thread per socket connection, to handle that connection and that connection only. We have one thread for our socket server, and it creates a new thread to handle each socket it accepts. (If you need an introduction to threads, I suggest you look athttp://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html or http://www.javaworld.com/javaworld/jw-04-1996/jw-04-threads.html or if all else fails, http://www.google.com/search?q=java+Threads.)
Each java program, when run, starts out with at least one thread. This is the thread that is going to process new connections in SimpleServer.java. Oddly, the SimpleServer class is even simpler than the VerySimpleServer class, but that is because we've moved some of the complexity out into a new class, SimpleHandler, which you can see below. When run, SimpleServer opens the server socket and waits for a new connection by calling ServerSocket.accept(). Once accept() returns with a new socket for the connection, SimpleServer creates a new instance of SimpleHandler to deal with the new socket, starts the new SimpleHandler, and then goes back to waiting for the next new connection.
SimpleHandler takes one already opened socket connection, and reads from that socket, and writes back what it has read to the other side. (Basically it echoes what is sent to it.) The only kind of weird thing is that it implements Runnable, and has a Thread member variable, myThread. When SimpleHandler.start() is called, it in turn calls myThread.start(this). The new thread is started, and calls SimpleHandler.run(). SimpleHandler.run() loops until the socket is closed, at which point it returns and the thread stops running.