<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent

    Vicent's blog
    隨筆 - 74, 文章 - 0, 評論 - 5, 引用 - 0
    數(shù)據(jù)加載中……

    一個Socket服務器樣板程序

    這是一個非常好的Socket服務器樣板程序,這個socket服務器可以為你建立指定的監(jiān)聽端口、客戶端請求響應機制等一些服務器所具備的基本框架



    /*

    * 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.

    */



    import java.io.*;

    import java.net.*;

    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 connections, and logs activity to a specified stream.

    **/

    public class Server {

    /**

    * 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 by the

    * specified password.

    **/

    public static void main(String[] args) {

    try {

    if (args.length < 2) // Check number of arguments

    throw new IllegalArgumentException("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

    int i = 0;

    while(i < args.length) {

    if (args[i].equals("-control")) { // Handle the -control arg

    i++;

    String password = args[i++];

    int port = Integer.parseInt(args[i++]);

    // add control service

    s.addService(new Control(s, password), port);

    }

    else {

    // Otherwise start a named service on the specified port.

    // Dynamically load and instantiate a Service class

    String serviceName = args[i++];

    Class serviceClass = Class.forName(serviceName);

    Service service = (Service)serviceClass.newInstance();

    int port = Integer.parseInt(args[i++]);

    s.addService(service, port);

    }

    }

    }

    catch (Exception e) { // Display a message if anything goes wrong

    System.err.println("Server: " + e);

    System.err.println("Usage: java Server " +

    "[-control ] " +

    "[ ... ]");

    System.exit(1);

    }

    }



    // This is the state for the server

    Map services; // Hashtable mapping ports to Listeners

    Set connections; // 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(OutputStream out) {

    if (out != null) logStream = new PrintWriter(out);

    else logStream = 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.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 hashtable

    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 IOException

    {

    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 accepting

    * connections

    ***/

    public void pleaseStop() {

    this.stop = true; // 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 them, and pass the socket on

    * to 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 service) {

    // 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 (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 limit */

    public synchronized void setMaxConnections(int max) {

    maxConnections = max;

    }



    /**

    * 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 use, this is the key feature that makes this a

    * multi-threaded server implementation.

    **/

    public class Connection extends 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);}

    finally { 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 typically 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 interface 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 reversal 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 serve(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 cannot 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 connected = 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 appear right away

    line = in.readLine(); // Get the user's input

    if (line == null) break; // 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 of the input and convert to lower case

    String command = 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 word

    if (p.equals(this.password)) { // 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 (!authorized) out.print("PASSWORD REQUIRED\n");

    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 occurred, add the service

    server.addService(service, port);

    out.print("SERVICE ADDED\n"); // acknowledge

    }

    }

    else if (command.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 Display

    if (!authorized) out.print("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");

    }

    else if (command.equals("quit")) break; // Quit command.

    else out.print("UNRECOGNIZED COMMAND\n"); // Error

    }

    catch (Exception e) {

    // If an exception occurred during the command, print an

    // error message, then output details of the exception.

    out.print("ERROR WHILE PARSING OR EXECUTING COMMAND:\n" +

    e + "\n");

    }

    }

    // Finally, when the loop command loop ends, close the streams

    // and set our connected flag to false so that other clients can

    // now connect.

    connected = false;

    out.close();

    in.close();

    }

    }

    }

    posted on 2006-08-24 15:13 Binary 閱讀(179) 評論(0)  編輯  收藏 所屬分類: j2se

    主站蜘蛛池模板: 亚洲午夜AV无码专区在线播放 | 免费视频专区一国产盗摄| 亚洲色av性色在线观无码| 国产成人精品日本亚洲专| 久久九九兔免费精品6| 亚洲视频在线观看地址| 99久久国产免费-99久久国产免费 99久久国产免费中文无字幕 | 一级一级毛片免费播放| 亚洲免费人成视频观看| 91亚洲国产成人久久精品| 日韩精品免费一线在线观看| 四虎在线播放免费永久视频| 亚洲高清不卡视频| 国产又大又粗又长免费视频| 亚洲熟女乱色一区二区三区| 亚洲AV无码一区二区三区国产 | 四虎永久免费网站免费观看| 污污污视频在线免费观看| 中文字幕亚洲综合久久男男| 国产免费AV片在线观看| 亚洲精品午夜在线观看| 日本阿v免费费视频完整版| 亚洲成av人片在www鸭子| 中文字幕免费在线看线人 | 亚洲va久久久噜噜噜久久天堂| 亚洲欧洲精品成人久久曰| 91人成网站色www免费下载| 亚洲av无码一区二区三区不卡| 91成人在线免费视频| 亚洲AV日韩AV一区二区三曲| 91手机看片国产永久免费| 妇女自拍偷自拍亚洲精品| 免费国产黄线在线观看| 日本特黄特色AAA大片免费| 久久亚洲精品国产精品| 免费鲁丝片一级观看| 中国黄色免费网站| 亚洲精品无码AV人在线播放| 在线观看成人免费视频不卡| 黄色毛片免费网站| 亚洲欧洲日本精品|