Simple Socket Examples.
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 at
http://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.
Last modified: Wed May 27 19:16:47 EDT 2009