Basic algorithm:
While true
Wait for an incoming request
Perform whatever actions are requested
In concept, it is really no different from a program that requires user interaction.
Detail of TCP/IP require a little more work:
Create an accepting socket on a "well known" port
While true
Wait for incoming connection
Communicate with client
Close socket
Use the java.net.ServerSocket class for servers.
(Note, if port is 0, a random port # will be assigned)
import java.net.*; public class SimpleTCPServer { public static void main(String[] args) { try { ServerSocket acceptor = new ServerSocket(0); System.out.println("On port " + acceptor.getLocalPort()); while (true) { Socket client = acceptor.accept(); // do stuff here client.close(); } } catch (IOException e) {} } }
TCP server that takes a command "date" and returns a string with the current date.
import java.net.*; import java.io.*; import java.util.Date; public class SimpleDateServer { public static void main(String[] args) throws IOException { ServerSocket acceptor = new ServerSocket(0); System.out.println("On port " + acceptor.getLocalPort()); while (true) { Socket client = acceptor.accept(); clientAction(client.getInputStream(), client.getOutputStream()); client.close(); } }
Why "new ServerSocket(0)"?
private static void clientAction(InputStream in, OutputStream out) throws IOException { DataInputStream parsedInput = new DataInputStream(in); PrintStream parsedOutput = new PrintStream(out); String inputLine = parsedInput.readLine(); if (inputLine.startsWith("date")) { Date now = new Date(); parsedOutput.println(now.toString()); } } }
Sample run of SimpleDateServer.
I typed everything in bold.
shelly: [151]--$ java SimpleDateServer & [2] 10087 shelly: [152]--$ On port 37978 telnet localhost 37978 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. date Tue Feb 11 12:25:57 PST 1997 Connection closed by foreign host. shelly: [153]--$ telnet localhost 37978 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello Connection closed by foreign host. shelly: [153]--$ fg java SimpleDateServer ^C shelly: [154]--$
Whatís wrong with this simple server?
Request processing blocks any other connections. (Iterative server)
Scenario 1:
Using our SimpleDateServer
Client A builds connection to server and goes to lunch
Client B builds connection to server andÖ
Scenario 2:
Using a server that given an integer n, it will compute all prime numbers with n digits.
Client A builds connection and sends 500
Client B builds connection andÖ
Solutions:
Multiple connections need to be accepted concurrently.
In some cases it may be valid to use a simple iterative server.
Rule of thumb:
If the time required to service a complete client-server request can be limited to a very short time, an iterative server can be used.
From this rule it follows that connection oriented (TCP) servers should never be of the iterative type.
Why?
A concurrent server can handle multiple requests concurrently.
Most TCP servers are of this kind.
Examples:
How is this done?
Two ways:
Super server:
Listens to multiple ports
Takes care of concurrency
Concurrency is handled by starting a new instance of the server for each new connection.
Pro:
Con:
Standalone server have several options:
Every one of these is a valid solution.
The server environment may not allow you to implement all of these.
For example:
Under Unix, the fork() system call is used to create new processes.
The fork() call creates a copy of the current process. It inherits many things including open file descriptors.
Terminology:
A parent forks to produce a child.
Basic algorithm:
Server creates an accepting socket Repeat forever { Wait for new client request Create a child (fork) The child will start dealing with the client. }
Concurrency in the implementation language is normally in the form of threads or something similar.
Threads can also be supported by the OS:
Difference between threads and processes:
Processes are independent of each other.
Threads can share address space
A process can have several threads
The algorithm is mostly the same as with concurrent processes.
Since threads share the same address space, Sockets can easily be passed from one thread to another.
(single process concurrent server)
Concurrency can be achieved with special OS support.
The key to this method is the use of non-blocking I/O operations.
For example:
Basic algorithm:
Create accepting socket Repeat forever { wait for ANY I/O operation. Depending on the type of operation, perform actions. }
Why worry about the different server types?
Why donít we always use the same one?
Issues:
For services that are used frequently (meaning many connections are made), creating a new process may be too slow.
Examples:
Other services are not used very frequently:
Other issues:
System resources:
A process (and to a lesser extend, a thread) take up system resources.
Normally there are also per-process or per-thread resource limits.
A single process is going to use up fewer resources, but may depleet some of them faster.
Other important resources:
The server platform can limit the types:
If a server needs to be ported to several platforms, only a common subset of features can be used.
Example:
Both Solaris and WindowsNT have threads, but they are not compatible.
Fortunately this is not an issue with Java since it is platform independent.