Menu
Java can run applications developed using the java programming language and set of development tools. The JVM is a crucial component of the Java platform. The availability of JVMs on many types of hardware and software platforms enables Java to function both as middleware and a platform in its own right. Socket Programming in Java This article describes a very basic one-way Client and Server setup where a Client connects, sends messages to server and the server shows them using socket connection. There’s a lot of low-level stuff that needs to happen for these things to work but the Java API networking package (java.net) takes care of all of.
Unit Goals
To gain proficiency in writing client-server applications in Java at the socket level.
Overview
We will look at four network applications, written completely from scratch in Java. Each of these applications use the client-server paradigm, which we discussed earlier. We’ll use TCP exclusively here. Recall that ports from 49152 to 65535 can be used for anything you want, so we’ll be using these.
Java’s abstraction over the socket API is to use a ServerSocket object that automatically listens, then creates a different socket on accept. Java sockets have input streams and output streams built in, which makes programming rather pleasant.
Four applications are presented in order of increasing complexity:
- A trivial date server and client, illustrating simple one-way communication. The server sends data to the client only.
- A capitalize server and client, illustrating two-way communication, and server-side threads to more efficiently handle multiple connections simultaneously.
- A two-player tic tac toe game, illustrating a server that needs to keep track of the state of a game, and inform each client of it, so they can each update their own displays.
- A multi-user chat application, in which a server must broadcast messages to all of its clients.
These applications communicate insecurely.
None of these applications even try to secure communication. All data is sent between hosts completely in the clear. The goal at this point is to illustrate the most basic applications and how they use transport-level services. In real life, use a secure sockets layer.
A Trivial Sequential Server
This is perhaps the simplest possible server. It listens on port 59090. When a client connects, the server sends the current datetime to the client. The connection socket is created in a try-with-resources block so it is automatically closed at the end of the block. Only after serving the datetime and closing the connection will the server go back to waiting for the next client.
Discussion:
- This code is just for illustration; you are unlikely to ever write anything so simple.
- This does not handle multiple clients well; each client must wait until the previous client is completely served before it even gets accepted.
- As in virtually all socket programs, a server socketjust listens, and a different, “plain” socket communicates with the client.
- The
ServerSocket.accept()
call is a BLOCKING CALL. - Socket communication is always with bytes; therefore sockets come with input streams and output streams. But by wrapping the socket’s output stream with a
PrintWriter
, we can specify strings to write, which Java will automatically convert (decode) to bytes. - Communication through sockets is always buffered. This means nothing is sent or received until the buffers fill up, or you explicitly flush the buffer. The second argument to the
PrintWriter
, in this casetrue
tells Java to flush automatically after everyprintln
. - We defined all sockets in a try-with-resources block so they will automatically close at the end of their block. No explicit
close
call is required. - After sending the datetime to the client, the try-block ends and the communication socket is closed, so in this case, closing the connection is initiated by the server.
Run the server:
To see that is running (you will need a different terminal window):
Test the server with
nc
:Woah
nc
is amazing! Still, let’s see how to write our own client in Java:DateClient.java
Discussion:
- On the client side, the
Socket
constructor takes the IP address and port on the server. If the connect request is accepted, we get a socket object to communicate. - Our application is so simple that the client never writes to the server, it only reads. Because we are communicating with text, the simplest thing to do is to wrap the socket’s input stream in a
Scanner
. These are powerful and convenient. In our case we read a line of text from the server withScanner.nextLine
.
Test the client:
A Simple Threaded Server
The previous example was pretty trivial: it did not read any data from the client, and worse, it served only one client at a time.
This next server receives lines of text from a client and sends back the lines uppercased. It efficiently handles multiple clients at once: When a client connects, the server spawns a thread, dedicated to just that client, to read, uppercase, and reply. The server can listen for and serve other clients at the same time, so we have true concurrency.
![Java Java](/uploads/1/2/6/2/126274297/933239758.png)
Discussion:
- The server socket, upon accepting a connection, does nothing more than fire off a thread.
- In Java, you should never create threads directly; instead, employ a thread pool and use an executor service to manage the threads.
- Limiting the thread pool size protects us against being swamped with millions of clients.
- The things that are run on threads are called tasks; they implement the
Runnable
interface; they do their work in theirrun
method. - Take care to never do too much work in the task’s constructor! The constructor is run on the main thread. Put all the work (other than capturing constructor arguments) in the
run
method. - The
run
method has a loop which keeps reading lines from the socket, uppercasing them, then sending them out. Note the wrapping of the socket streams in aScanner
and aPrintWriter
so that we can work with strings. - The
finally
block closes the socket. We could not use a try-with-resources block here because the socket was created on the main thread. - The annoying try-catch around the socket close call has to be there because we cannot add
throws IOException
to therun
method signature (because we are implementing it from theRunnable
interface.
Before writing a client, let’s test with
nc
. Our server reads until standard input is exhausted, so when you are done typing in lines, hit Ctrl+D (clean exit) or Ctrl+C (abort):Now for a pretty simple command line client:
CapitalizeClient.java
This client repeatedly reads lines from standard input, sends them to the server, and writes server responses. It can be used interactively:
Or you can pipe in a file!
Classwork
Get into groups of two. One student will start a server in one terminal window and a client in another, and start each. The other student will create two terminal windows each running a client. Before any of the three clients send any data to the server, runnetstat
to make sure you see the listening server and all of the client connections. (On a Mac,netstat -an | grep tcp | grep 59898
is useful to see just the good stuff.) Correlate the netstat output with the log messages echoed by the server and client. As data is sent, keep running netstat. Watch the connections go from ESTABLISHED to TIME_WAIT, and then disappear. Make notes of everything that happens; we’ll discuss as a group when everyone’s done.
A Network Tic-Tac-Toe Game
Here is the server for multiple two-player games. It listens for two clients to connect, and spawns a thread for each: the first is Player X and the second is Player O. The client and server send simple string messages back and forth to each other; messages correspond to the Tic Tac Toe protocol, which I made up for this example.
These days, games like this would be played with clients in a web browser, and the server would be a web server (likely using a WebSockets library). But today, we’re learning about programming directly with sockets, on custom ports, with custom protocols, so we’re sticking with Java for our custom clients. The first version of this program was written in about 2002, so it uses...wait for it...Java Swing!
TicTacToeClient.java
Exercise: Play this game in
nc
. How awesome is this? Do you feel old school?A Multi-User Chat Application
Here is a chat server. The server must broadcast recently incoming messages to all the clients participating in a chat. This is done by having the server collect all of the client sockets in a dictionary, then sending new messages to each of them.
Here’s an old client cobbled together in 2002, using Swing.
ChatClient.java
Exercise: Enhance the protocol so that it distinguishes system messages (such as people joining and leaving), from chat messages, then enhance the client so that it uses color and fonts to highlight the different kinds of messages.
Summary
We’ve covered:
- A review of the client-server model
- One-way communication between client and server
- Two-way communication between client and server
- Using threads on the server
- Keeping track of state in a network-based multiplayer game
- How a server can broadcast messages to multiple clients.
- The awesome nc utility
- Some...uh...Java Swing
Unit Goals
To gain proficiency in writing client-server applications in Java at the socket level.
Overview
We will look at four network applications, written completely from scratch in Java. Each of these applications use the client-server paradigm, which we discussed earlier. We’ll use TCP exclusively here. Recall that ports from 49152 to 65535 can be used for anything you want, so we’ll be using these.
Java’s abstraction over the socket API is to use a ServerSocket object that automatically listens, then creates a different socket on accept. Java sockets have input streams and output streams built in, which makes programming rather pleasant.
Four applications are presented in order of increasing complexity:
- A trivial date server and client, illustrating simple one-way communication. The server sends data to the client only.
- A capitalize server and client, illustrating two-way communication, and server-side threads to more efficiently handle multiple connections simultaneously.
- A two-player tic tac toe game, illustrating a server that needs to keep track of the state of a game, and inform each client of it, so they can each update their own displays.
- A multi-user chat application, in which a server must broadcast messages to all of its clients.
These applications communicate insecurely.
None of these applications even try to secure communication. All data is sent between hosts completely in the clear. The goal at this point is to illustrate the most basic applications and how they use transport-level services. In real life, use a secure sockets layer.
A Trivial Sequential Server
This is perhaps the simplest possible server. It listens on port 59090. When a client connects, the server sends the current datetime to the client. The connection socket is created in a try-with-resources block so it is automatically closed at the end of the block. Only after serving the datetime and closing the connection will the server go back to waiting for the next client.
Discussion:
- This code is just for illustration; you are unlikely to ever write anything so simple.
- This does not handle multiple clients well; each client must wait until the previous client is completely served before it even gets accepted.
- As in virtually all socket programs, a server socketjust listens, and a different, “plain” socket communicates with the client.
- The
ServerSocket.accept()
call is a BLOCKING CALL. - Socket communication is always with bytes; therefore sockets come with input streams and output streams. But by wrapping the socket’s output stream with a
PrintWriter
, we can specify strings to write, which Java will automatically convert (decode) to bytes. - Communication through sockets is always buffered. This means nothing is sent or received until the buffers fill up, or you explicitly flush the buffer. The second argument to the
PrintWriter
, in this casetrue
tells Java to flush automatically after everyprintln
. - We defined all sockets in a try-with-resources block so they will automatically close at the end of their block. No explicit
close
call is required. - After sending the datetime to the client, the try-block ends and the communication socket is closed, so in this case, closing the connection is initiated by the server.
Run the server:
To see that is running (you will need a different terminal window):
Test the server with
nc
:Woah
nc
is amazing! Still, let’s see how to write our own client in Java:DateClient.java
Discussion:
- On the client side, the
Socket
constructor takes the IP address and port on the server. If the connect request is accepted, we get a socket object to communicate. - Our application is so simple that the client never writes to the server, it only reads. Because we are communicating with text, the simplest thing to do is to wrap the socket’s input stream in a
Scanner
. These are powerful and convenient. In our case we read a line of text from the server withScanner.nextLine
.
Test the client:
A Simple Threaded Server
The previous example was pretty trivial: it did not read any data from the client, and worse, it served only one client at a time.
This next server receives lines of text from a client and sends back the lines uppercased. It efficiently handles multiple clients at once: When a client connects, the server spawns a thread, dedicated to just that client, to read, uppercase, and reply. The server can listen for and serve other clients at the same time, so we have true concurrency.
Discussion:
- The server socket, upon accepting a connection, does nothing more than fire off a thread.
- In Java, you should never create threads directly; instead, employ a thread pool and use an executor service to manage the threads.
- Limiting the thread pool size protects us against being swamped with millions of clients.
- The things that are run on threads are called tasks; they implement the
Runnable
interface; they do their work in theirrun
method. - Take care to never do too much work in the task’s constructor! The constructor is run on the main thread. Put all the work (other than capturing constructor arguments) in the
run
method. - The
run
method has a loop which keeps reading lines from the socket, uppercasing them, then sending them out. Note the wrapping of the socket streams in aScanner
and aPrintWriter
so that we can work with strings. - The
finally
block closes the socket. We could not use a try-with-resources block here because the socket was created on the main thread. - The annoying try-catch around the socket close call has to be there because we cannot add
throws IOException
to therun
method signature (because we are implementing it from theRunnable
interface.
Before writing a client, let’s test with
nc
. Our server reads until standard input is exhausted, so when you are done typing in lines, hit Ctrl+D (clean exit) or Ctrl+C (abort):Now for a pretty simple command line client:
CapitalizeClient.java
This client repeatedly reads lines from standard input, sends them to the server, and writes server responses. It can be used interactively:
Or you can pipe in a file!
Classwork
Get into groups of two. One student will start a server in one terminal window and a client in another, and start each. The other student will create two terminal windows each running a client. Before any of the three clients send any data to the server, runnetstat
to make sure you see the listening server and all of the client connections. (On a Mac,netstat -an | grep tcp | grep 59898
is useful to see just the good stuff.) Correlate the netstat output with the log messages echoed by the server and client. As data is sent, keep running netstat. Watch the connections go from ESTABLISHED to TIME_WAIT, and then disappear. Make notes of everything that happens; we’ll discuss as a group when everyone’s done.
A Network Tic-Tac-Toe Game
Here is the server for multiple two-player games. It listens for two clients to connect, and spawns a thread for each: the first is Player X and the second is Player O. The client and server send simple string messages back and forth to each other; messages correspond to the Tic Tac Toe protocol, which I made up for this example.
These days, games like this would be played with clients in a web browser, and the server would be a web server (likely using a WebSockets library). But today, we’re learning about programming directly with sockets, on custom ports, with custom protocols, so we’re sticking with Java for our custom clients. The first version of this program was written in about 2002, so it uses...wait for it...Java Swing!
TicTacToeClient.java
Exercise: Play this game in
nc
. How awesome is this? Do you feel old school?A Multi-User Chat Application
Here is a chat server. The server must broadcast recently incoming messages to all the clients participating in a chat. This is done by having the server collect all of the client sockets in a dictionary, then sending new messages to each of them.
Here’s an old client cobbled together in 2002, using Swing.
ChatClient.java
Exercise: Enhance the protocol so that it distinguishes system messages (such as people joining and leaving), from chat messages, then enhance the client so that it uses color and fonts to highlight the different kinds of messages.
Summary
We’ve covered:
- A review of the client-server model
- One-way communication between client and server
- Two-way communication between client and server
- Using threads on the server
- Keeping track of state in a network-based multiplayer game
- How a server can broadcast messages to multiple clients.
- The awesome nc utility
- Some...uh...Java Swing