Programming | server | network
The Java Socket API provides a convenient object interface for network programming. This article uses a simple TCP Echo server as an example to demonstrate how to use Java to complete a network server.
The TCP Echo server used as an example works in the following ways:
When a client connects to the server over TCP, the client can send data to the service side through the connection, and the service side receives the data and sends the data back to the client with the same TCP connection. The server will keep this connection until the client closes it.
Because the server needs to be able to handle multiple clients at the same time, we first choose a common multithreaded service model:
Let a thread monitor the service port, and when a new connection is established, this listener thread creates a new thread for the connection to handle it. This allows the server to accept multiple connections and allow multiple thread to handle them separately.
The following are the appropriate server-side programs:
|
public class Echoserver implements Runnable { public void Run () { try { ServerSocket svr = new ServerSocket (7); while (true) { Socket sock = svr.accept (); New Thread (New Echosession (sock)). Start (); } catch (IOException ex) { throw new Exceptionadapter (ex); } } } |
This code first creates a ServerSocket object and listens on TCP port 7, then receives a new connection in a loop using the Accept () method, and creates a thread to handle the connection. The logic that actually handles each client connection is contained within the Echosession class.
The Exceptionadapter class is used in the above code to wrap a checked exception into a runtimeexception. Detailed instructions can be referenced to avoid using checked Exception in Java.
Here's the code for Echosession:
|
public class Echosession implements Runnable { Public Echosession (Socket s) { _sock = s; } public void Run () { |
|
try { try { InputStream input = _sock.getinputstream (); OutputStream output = _sock.getoutputstream (); byte [] buf = new byte [128]; while (true) { int count = Input.read (BUF); if (count = = 1) Break Output.write (buf, 0, Count); } finally { _sock.close (); } catch (IOException ex) { throw new Exceptionadapter (ex); } } protected Socket _sock = null; } |
Echosession accepts a socket object as the constructor parameter, and in its run () method, it constantly reads the data from the InputStream of the socket object and writes it back into the outputstream of the socket. Until this connection is closed by the client (InputStream Read method returns-1).
Echosession needs a thread to execute, which makes it easy to associate with thread as the parent of echosession. However, this is not flexible enough, the cost is relatively large. And the choice lets echosession realize runnable interface to be much more flexible. You can see this in the next echo server that uses thread pool.
The above is already a complete TCP Echo server, but as customers are constantly connected and disconnected, the server will continue to generate and eliminate threads, both of which are more ' expensive ' operations. To avoid this consumption, the mechanism of thread pool can be considered.
Using the implementation of thread pool in the implementation of a simple thread buffer pool, Echoserver can be modified as follows (Echosession need not be modified):
|
public class Echoserver implements Runnable { public void Run () { try { ServerSocket svr = new ServerSocket (7); |
|
Initializing thread Pool Syncqueue queue = new Syncqueue (10); for (int i = 0; i < i + +) { New Thread (new Worker (queue)). Start (); } while (true) { Socket sock = svr.accept (); Put the task into the thread Pool Queue.put (New Echosession (sock)); } catch (IOException ex) { throw new Exceptionadapter (ex); } } } |
Here you can see the flexibility of making echosession implement the Runnable interface, which you can use in the thread pool without modifying it.
The thread pool used in this example is relatively simple, without the ability to dynamically adjust the thread count, so this echo server can serve only 10 clients at a time. However, by overloading Syncqueue, we can easily add this feature to break through this limitation.
When the performance and concurrency requirements of a network server are high, it may not be possible for each client to be handled by a dedicated thread (imagine a thousands of-client situation at the same time). Consider using the Java NIO API to build the server architecture, because IO operations in NIO are non-blocking, and we need very little thread to fully utilize the CPU to handle requests from multiple clients. On the topic of NIO, in this article will not repeat, I hope to have the opportunity to discuss. :)