- There are a couple differences with servers:
- They have to start running first.
- They need an extra port -- one to listen for clients.
- But once a server has made the connection to the client, it's
really just the same.
- Here is yet more code from David Barnes -- this time I left the
main as he wrote it (in another class) though I really don't see the
advantage... (so no comment claiming I'm a coauthor!)
- The server class
import java.net.*;
import java.io.*;
// A simple server that accepts a client connection
// and sends back the length of the strings it
// receives from the client.
class LineLengthServer {
public LineLengthServer(int port) throws Exception {
try{
// Listen on the given port.
serverSocket = new ServerSocket(port);
}
catch(BindException e){
throw new Exception("Failed to create a server socket: "+
e.getMessage());
}
}
// Read strings and return their length (as a String)
// to the client.
public void run() throws Exception {
ServerSocket serverSocket = getServerSocket();
Socket clientSocket = null;
try{
System.out.println("Listening for a client on port: "+
serverSocket.getLocalPort());
// Wait for a client to make contact.
clientSocket = serverSocket.accept();
// Contact ...
System.out.println("A client has arrived.");
// Wrap the input stream in a BufferedReader.
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
// Wrap the output stream in a BufferedWriter.
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()));
// Read lines until the client terminates.
String request = reader.readLine();
while(request != null){
// Write the length of the line as a String.
writer.write(String.valueOf(request.length()));
writer.newLine();
writer.flush();
request = reader.readLine();
}
}
catch(IOException e){
throw new Exception("IOException talking to the client: "+
e.getMessage());
}
finally{
if(clientSocket != null){
System.out.println("The client has gone.");
// Close the socket to the client.
clientSocket.close();
}
}
serverSocket.close();
}
protected ServerSocket getServerSocket(){
return serverSocket;
}
// The socket on which the listening is done.
private final ServerSocket serverSocket;
}
- The "main" class
// An example of a simple server that reads lines from
// clients and sends back the length of each line
// it receives.
public class LineLengthServerMain {
public static void main(String[] args){
try{
// An arbitrary port number to listen on. This should be
// larger than 1024 for user-written servers.
final int port = 24101;
LineLengthServer server = new LineLengthServer(port);
server.run();
}
catch(Exception e){
System.err.println("Exception: "+e.getMessage());
}
}
}
- Running it from linux
[joanna@sydney Networks]$ javac LineLengthServerMain.java
[joanna@sydney Networks]$ java LineLengthServer
Exception in thread "main" java.lang.NoSuchMethodError: main
[joanna@sydney Networks]$ java LineLengthServerMain
Listening for a client on port: 24101
^Z
[2]+ Stopped java LineLengthServerMain
[joanna@sydney Networks]$ bg
[2]+ java LineLengthServerMain &
[joanna@sydney Networks]$ telnet localhost 24101
Trying 127.0.0.1...
A client has arrived.
Connected to localhost.
Escape character is '^]'.
hi there
8
have you ever thought
21
this isn't really measuring the line length...
46
Ah ha!
6
^]
telnet> .
?Invalid command
telnet> quit
Connection closed.
The client has gone.
[2]+ Done java LineLengthServerMain
[joanna@sydney Networks]$
- Notice I used telnet as a client again (see colour
code mentioned earlier).
- And also, I suspended the server
process (with ^Z) and then
backgrounded it by typing bg
- This made it start running
run, but leaving me STDIN to use with telnet.
- You can also type fg and get right back where you
were.
- You could also start the
server in the background in the first place by typing an &
afterwards like this: j2bryson$
java LineLengthServerMain &
- Note both programs
now shared STDOUT!
- Consequently, both programs were printing to the screen at the
same time -- telent I made blue, the server red, and what I typed green.
- I also forgot the telnet
protocol / commands -- I thought you
killed it with a .
- mail quites with a .
- I got it right the second
guess though.
- Don't be afraid to
hack!
- If you want to make a server accept more than one connection,
just put a while loop in so it looks again (see the outlined server
back in section I.)
- If you want to have the server accept new clients while it's
still servicing old ones, you need to use threads!
- Here's an example of that, again from Barnes (hey, he writes good
examples! This is from RandomServiceListener)
public void listen() throws Exception {
ServerSocket serverSocket = getServerSocket();
// Wait up to 30 minutes for new clients.
final int timeToWait = 1*60*1000;
boolean keepWaiting = true;
while(keepWaiting){
try{
// Wait for a client to make contact.
serverSocket.setSoTimeout(timeToWait);
Socket clientSocket = serverSocket.accept();
// Let a separate Thread handle it.
new Thread(new RandomService(clientSocket)).start();
}
catch(InterruptedIOException e){
// We timed out waiting for a client.
keepWaiting = false;
}
catch(IOException e){
throw new Exception("IOException: "+ e.getMessage());
}
}
// No more clients, so close the socket.
serverSocket.close();
}
- Notice not only the threading, but the fact it handles
interupts, so it can eventually be killed!
- It also sets a timeout
so that it will effectively interrupt itself if it's been waiting too
long (as well as accepting terminate signals, e.g. from the keyboard.)