Socket Server program

xiaoxiao2021-03-06  40

Perfect Socket Server program selection from skyyoung's Blog / * * Copyright (c) 2000 David Flanagan. All rights reserved. * This code is from the book Java Examples in a Nutshell, 2nd Edition. * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied. * you may study, use, and modify it for any non-commercial purpose. * you may distribute it non-commercially as long as you retain this notice. * for a commercial use license, or to purchase The Book (Recommended), * Visit http://www.davidflanagan.com/javaexamples2. * / package com.davidflanage.examples.net; import java.io. *; import java.util. *; / ** * This class is a generic framework for a flexible, multi-threaded server * It listens on any number of specified ports, and, when it receives a * connection on a port, passes input and output streams to a. Specified Service * Object Which Provides The Actual Service. It can limit the number of * concurrent connects, and logs activity to a specified stream. ** / public class se rver {/ ** * A main () method for running the server as a standalone program. The * command-line arguments to the program should be pairs of servicenames * and port numbers. For each pair, the program will dynamically load the * named Service class, instantiate it, and tell the server to provide * that Service on the specified port. The special -control argument * should be followed by a password and port, and will start special * server control service running on the specified port, Protected password. ** / public static void main (string [] args) {try {if (args.length <2) // Check number of arguments throw new illegalgumentexception ("

Must specify a service "); // Create a Server Object That Uses Standard Out As ITS log and // HAS a limit of Ten Concurrent Connections at Once. Server S = New Server (System.out, 10); // Parse THE Argument List I = 0; While (I ]" "[ ..."); System . e it t;;;;;;;

// The set of current connections int maxConnections; // The concurrent connection limit ThreadGroup threadGroup; // The threadgroup for all our threads PrintWriter logStream; // Where we send our logging output to / ** * This is the Server () constructor . It must be passed a stream * to send log output to (may be null), and the limit on the number of * concurrent connections ** / public Server (OutputStream logStream, int maxConnections) {setLogStream (logStream);. log ( "Starting server"); threadGroup = new threadGroup (Server.class.getName ()); this.maxConnections = maxConnections; services = new HashMap (); connections = new HashSet (maxConnections);} / ** * A public method to set the current logging stream Pass null * to turn logging off ** / public synchronized void setLogStream logStream (OutputStream out) {if (out = null!) = new PrintWriter (out);. else logS Tream = null;} / ** Write the specified string to the log * / protected synchronized void log (string s) {if (logstream! = null) {logStream.println ("[" new date () "]" S); logstream.flush ();}} / ** Write the specified object to the log * / protected void log (Object O) {log (o.to.tostring ());} / ** * this method Makes The server start providing a new service * It runs the specified Service object on the specified port ** / public synchronized void addService (Service service, int port) throws IOException {Integer key = new Integer (port)..;

// The Hashtable Key // Check WHETHER A Service IS Already On That Port IF (Services.get (KEY)! = NULL) Throw new IllegalargumentException ("port" port "already in use."); // Create A listener object to listen for connections on the port listener listener = new listener (threadGroup, port, service); // Store it in the hashtable services.put (key, listener); // log it log ( "Starting service" service .getclass (). getName () "on port" port); // start the listener running. listener.start ();} / ** * this method makes the server stop providing a service on a port. * IT does not terminate any pending connections to that service, merely * causes the server to stop accepting new connections ** / public synchronized void removeService (int port) {Integer key = new Integer (port); // hashtable key // Look up the Listener Object for the port in the hash Table Final Listener Listener = (listener) Services.get (key); if (listener == null) Return; // ask the listener to stop listener.pleasestop (); // remove it from the hashtable services.remove (key) // and log it. Log ("stopping service" listener.service.getClass (). Getname () "on port" port);} / ** * this nested thread subclass is a "listener"

. It listens for * connections on a specified port (using a ServerSocket) and when it gets * a connection request, it calls the servers addConnection () method to * accept (or reject) the connection. There is one Listener for each * Service . being provided by the Server ** / public class Listener extends Thread {ServerSocket listen_socket; // The socket to listen for connections int port; // The port we're listening on Service service; // The service to provide on that port volatile boolean stop = false; // Whether we've been asked to stop / ** * The Listener constructor creates a thread for itself in the * threadgroup It creates a ServerSocket to listen for connections * on the specified port It arranges for.. The Serversocket To Be * Interruptible, So That Services Can Be Removed from The Server. ** / Public Listener (ThreadGroup Group, Int Port, Service Service) Throws I OException {super (group, "Listener:" port); listen_socket = new ServerSocket (port); // give it a non-zero timeout so accept () can be interrupted listen_socket.setSoTimeout (600000); this.port = port THIS.Service = service;} / ** * this is the polite way to get a listener to stop access * connection/** / public void please; // set the stop flag this. Interrupt (); // stop blocking in accept () try {listen_socket.close ();

} // stop listening. Catch (ioexception e) {}} / ** * a listener is a thread, and this is its body. * Wait for connection requests, accept the addconnection method of { The Server. ** / public void Run () {While (! stop) {// loop Until We're asked to stop. Try {socket client = listen_socket.accept (); addconnection (client, service);} catch InterruptedIOException e) {} catch (IOException e) {log (e);}}}} / ** * This is the method that Listener objects call when they accept a * connection from a client It either creates a Connection object * for. the connection and adds it to the list of current connections, * or, if the limit on connections has been reached, it closes the * connection. ** / protected synchronized void addConnection (Socket s, Service s ervice) {// If the connection limit has been reached if (connections.size ()> = maxConnections) {try {// Then tell the client it is being rejected PrintWriter out = new PrintWriter (s.getOutputStream ()).; Out.print ("Connection Refused;" "The Server IS Busy; Please Try Again Later./N"); Out.Flush (); // and close the connection to the rejected client. s.close (); / / And log it, of course log ("Connection Refused to" S.Getinetaddress (). GetHostaddress () ":" S.Getport () ": max connections reached.");} Catch (ion (IOException E) {log (e);

}} Else {// Otherwise, if the limit has not been reached // Create a Connection thread to handle this connection Connection c = new Connection (s, service); // Add it to the list of current connections connections.add ( c); // log this new connection log ("Connected to" s.Getinetaddress (). getHostaddress () ": S.Getport () " on port " s.getlocalport () " for service " service.getClass (). getName ()); // and start the connection thread to provide the service c.start ();}} / ** * a connection thread calls this method just before it exits. it removes * the specified Connection from the set of connections ** / protected synchronized void endConnection (Connection c) {connections.remove (c); log ( "Connection to" c.client.getInetAddress () getHostAddress () .. ":" c.client.getPort () "closed.");} / ** Change the current connection limited * / public synchronized void setMaxConnections (int max) {maxconnections = m ax;..} / ** * This method displays status information about the server on the * specified stream It can be used for debugging, and is used by the * Control service later in this example ** / public synchronized void displayStatus (PrintWriter Out) {// Display a list of all services That Are Being provided iterator keys = services.keyset (). iterator (); while (keys.hasnext ()) {Integer port = (integer) keys.next (); listener Listener = (listener) Services.get (port); Out.print ("Service" listener.Service.getClass (). getName () "on port" port

"/ n");} // display the current connection limit out.print ("Max Connections:" MaxConnections "/ N"); // Display a list of all current connections iterator connS = connections.iterator (); While (Conns.hasNext ()) {Connection C = (Connection) Conns.next (); Out.print ("Connected to" C. Client.getinetaddress (). getHostAddress () ":" C.Client. GETPORT () "on port" c.client.getlocalport () "for service" C.Service.getClass (). getName () "/ n");}} / ** * this class is a subclass of Thread that handles an individual * connection between a client and a Service provided by this server. * Because each such connection has a thread of its own, each Service can * have multiple connections pending at once. Despite all the other * threads in Uses, this is the key feature tria, this a * multi-threaded series a * multi-threaded series limited eXtens thread {socket client; // the socket to talk to the client through Service service; // The service being provided to that client / ** * This constructor just saves some state and calls the superclass * constructor to create a thread to handle the connection Connection * objects are created by Listener threads. . These threads are part of * the server's ThreadGroup, so all Connection threads are part of that * group, too ** / public Connection (Socket client, Service service) {super ( "Server.Connection:". client.getInetAddress ( ) .gethostaddress () ":" client.getPort ());

this.client = client; this.service = service;.} / ** * This is the body of each and every Connection thread * All it does is pass the client input and output streams to the * serve () method of the specified Service object. that method is * responsible for reading from and writing to those streams to * provide the actual service. Recall that the Service object has * been passed from the Server.addService () method to a Listener * object to the addConnection () method to this Connection object, and * is now finally being used to provide the service. Note that just * before this thread exits it always calls the endConnection () method * to remove itself from the set of connections ** / public void run ( ) {Try {INPUTSTREAM IN = Client.getinputStream (); OutputStream out = client.getOutputStream (); service.serve (in, out);} catch (ioException e) {log (e);} fin Ally {endConnection (this);

}}} / ** * Here is the Service interface that we have seen so much of. It defines * only a single method which is invoked to provide the service. Serve () * will be passed an input stream and an output stream to the client. It * should do whatever it wants with them, and should close them before * returning. * * All connections through the same port to this service share a single * Service object. Thus, any state local to an individual connection must * be stored in local variables within the serve () method. State that * should be global to all connections on the same port should be stored * in instance variables of the Service class. If the same Service is * running on more than one port, THERE WILL TYPICLY BE DIFFERENT * Service Instances for Each Port. Data That Should Be Global To All * Connections On Any Port Should Be Stored In Static Variables. * * Note That Implementations of this Interfac e must have a no-argument * constructor if they are to be dynamically instantiated by the main () * method of the Server class ** / public interface Service {public void serve (InputStream in, OutputStream out) throws IOException;}. / ** * A very simple service. It displays the current time on the server * to the client, and closes the connection. ** / public static class Time implements Service {public void serve (InputStream i, OutputStream o) throws IOException {PrintWriter OUT = New PrintWriter (O); OUT.PRINT (new date () "/ n"); out.close (); i.close ();

}} / ** * This is another example service. It reads lines of input from the * client, and sends them back, reversed. It also displays a welcome * message and instructions, and closes the connection when the user * enters a ' . 'on a line by itself ** / public static class Reverse implements Service {public void serve (InputStream i, OutputStream o) throws IOException {BufferedReader in = new BufferedReader (new InputStreamReader (i));. PrintWriter out = new PrintWriter ( NEW BufferedWriter (New OutputStreamWriter (O)); Out.print ("Welcome to the line reverseal server./n"); out.print ("Enter Lines. End with a '.' on a line by itself./n "); For (;;) {out.print ("> "); out.flush (); string line = in.readline (); if (((line == null) || line.equals (". " )) Break; for (int J = line.length () - 1; j> = 0; J -) Out.Print (line.charat (j)); out.print ("/ n");} out.close (); in.close ();}} / ** * this service is an http mirror, Just Like the HttpMirror class * implemented earlier in this chapter. It echos back the client's * HTTP request ** / public static class HTTPMirror implements Service {public void serve (InputStream i, OutputStream o) throws IOException {BufferedReader in = new BufferedReader (new InputStreamReader ( I)); PrintWriter Out = New PrintWriter (O); OUT.PRINT ("HTTP / 1.0 200 / N");

Out.print ("Content-Type: Text / Plain / N / N"); String line; while ((line = in.readline ())! = null) {if (line.length () == 0) Break Out.Print (Line "/ N");} out.close (); in .close ();}} / ** * this service demonstrates how to maintain state across connections by * saving it in instance variables and using . synchronized access to those * variables It maintains a count of how many clients have connected and * tells each client what number it is ** / public static class UniqueID implements Service {public int id = 0; public synchronized int nextId () {return ID ;} public void service (InputStream I, OutputStream O) throws ioException {printwriter out = new printwriter (O); OUT.PRINT ("You are client #:" nextId () "/ n"); out.close (); I.close ();}} / ** * this is a non-trivial service. .. It implements a command-based protocol * that gives password-protected runtime control over the operation of the * server See the main () method of the Server class to see how this * service is started * * The recognized commands are: * Password: give password;

authorization is required for most commands * add: dynamically add a named service on a specified port * remove: dynamically remove the service running on a specified port * max: change the current maximum connection limit * status:. display current services, connections, and connection limit * help: display a help message * quit: disconnect * * This service displays a prompt, and sends all of its output to the user * in capital letters Only one client is allowed to connect to this * service at a time.. ** / public static class Control implements Service {Server server; // The server we control String password; // The password we require boolean connected = false; // Whether a client is already connected / ** * Create a new Control service . IT Will Control The Specified Server * Object, And Will Require The Specified Password for Authorization * Note that this Service does not have a no argument constructor, * which means that it can not be dynamically instantiated and added as * the other, generic services above can be. ** / public Control (Server server, String password) {this.server = server; this.password = password;} / ** * This is the serve method that provides the service It reads a * line the client, and uses java.util.StringTokenizer to parse it * into commands and arguments It does various.. Things Depending on * The command. ** / public void Serve (InputStream I, OutputStream O) throws ioException {// setup the streams bufferedreader in =

new BufferedReader (new InputStreamReader (i)); PrintWriter out = new PrintWriter (o); String line; // For reading client input lines // Has the user has given the password yet boolean authorized = false;? // If there is already a client connected to this service, display // a message to this client and close the connection. We use a // synchronized block to prevent a race condition. synchronized (this) {if (connected) {out.print ( "ONLY One Control Connection Allowed./N "); out.close (); return;} else connection = true;} // this is the main loop: read a command, parse it, and handle it for (;;) {/ / Infinite loop out.print (">"); // Display a prompt out.flush (); // make it it is appear right away line = in.readline ); // get the user's infutiff; // quit if we get eof. Try {// use a StringTokenizer to Parse the user's command StringTokenizer T = New StringTokenizer (line); if (! T .hasmoretoKens ()) Continue; // if INPUT WAS EMPTY / / GET FIRST WORD WASE INPUT = T.NEXTTOKEN (). TOLOWERCASE (); // NOW Compare To Each of the Possible Commands, Doing the // appropriate Thing for Each Command IF (Command.equals ("Password"

)) {// password command string p = t.nextToken (); // get the next wordiff {// is it the password? Out.print ("ok / n" ); // Say so authorized = true; // grant authorization} else out.print ("invalid password / n"); // OtherWise Fail} Else IF (Command.equals ("add")) {// add service command // Check whether password has been given if out.print ( "pASSWORD REQUIRED / n") (authorized!); else {// Get the name of the service and try to // dynamically load and instantiate it // Exceptions. Will Be Handled Below String ServiceName = T.NEXTTOKEN (); Class ServiceClass = Class.forName (serviceName); Service service; try {service = (Service) serviceClass.newInstance ();} catch (NoSuchMethodError e) {throw new IllegalArgumentException ( "Service must have a" "no-argument constructor");} INT port = integer.parseint (T.NEXTTOKEN ()); // if no exceptions ocdservice (service, port); out.print ("Service Added / N");

// Acknowledge}} Else IF ("Remand.equals (" Remove ") {// Remove Service if (! authorized) Out.print (" Password Required / N "); Else {Int port = integer.parseint (t. NextToken ()); server.removeService (port); // Remove the service out.print ("service removed / n"); // Acknowledge}} else if (Command.equals ("max")) {// set Connection Limit if (! Authorized) Out.print ("Password Required / N"); Else {Int Max = Integer.Parseint (T.NextToken ()); Server.SetMaxConnections (max); Out.print ("Max Connections Changed / N ");}} else if (Command.Equals (" status ")) {// status di SPLAY IF ("Password Required / N"); Else Server.DisplayStatus (OUT);} else IF (Command.Equals ("Help")) {// Help Command // Display Command Syntax. Password NOT Required Out.print ("Commands: / N" "/ TPassword / n" "/ tadd / n" "/ Tremove / n" "/ tmax / n " " / tstatus / n " " / thelp / n " " / tquit / n ");

转载请注明原文地址:https://www.9cbs.com/read-69925.html

New Post(0)