java安全机制其实有点不安全

看下面的这段代码,摘自《Java Examples in a Nutsbell》(java实例技术手册):

就是一个简单的通用的多线程服务器

这个例子可以通过配置参数:

java je3.net.Server -control www 3333 je3.net.Server$HTTPMirror 5555

来启动,然后再ie中输入:  http://localhost:5555就可以看到效果。

写一个policy文件放在同根目录下:叫server.policy

grant{
   permission java.net.SocketPermission "*:1024-4444","connect,accept"; 
   permission java.io.FilePermission "E://workspace//j2ee1.3//-", "read";
};

下面加上jvm虚拟机参数

java -Djava.security.manager -Djava.security.policy=server.policy

je3.net.Server -control www 3333 je3.net.Server$HTTPMirror 5555再次启动。

按道理,本不应该启动。因为端口5555并没有得到连接许可。但是很可惜输入 http://localhost:5555还是可以看到结果。因为在java的sdk中暗含了java.policy文件。那就把它改为-Djava.security.policy==server.policy应该就可以了。结果跑不了了。原因就在policy文件中的permission java.net.SocketPermission "*:1024-4444","connect,accept"; 其实,我一直不太清楚listen ,accept,connect的区别在什么地方。但是这里的例子说明你只用permission java.net.SocketPermission "*:1024-4444","listen";就可以了。端口该闭的就闭了。如果用accept和connect反而没有什么用。不知道java的安全性高在什么地方。因为java.policy文件中从1024以上的端口全都使用了listen。所以以后要配置端口时一定要注意。

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd 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,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit 
http://www.davidflanagan.com/javaexamples3.
 
*/

package  je3.net;
import  java.io. * ;
import  java.net. * ;
import  java.util. * ;
import  java.util.logging. * ;

/**
 * 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 has a limit of 10 concurrent
        
// connections, and logs to a Logger at the Level.INFO level
        
// Prior to Java 1.4 we did this: new Server(System.out, 10);
        Server s = new Server(Logger.getLogger(Server.class.getName()),
                  Level.INFO, 
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 <password> <port>] " +
                   
"[<servicename> <port> ... ]");
            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

    
// This class was originally written to send logging output to a stream.
    
// It has been retrofitted to also support the java.util.logging API of
    
// Java 1.4.  You can use either, neither, or both.
    PrintWriter logStream;          // Where we send our logging output to
    Logger logger;                  // A Java 1.4 logging destination
    Level logLevel;                 // the level to log messages at

    
/**
     * 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) 
    
this(maxConnections);
        setLogStream(logStream);
        log(
"Starting server");
    }


    
/**
     * This constructor added to support logging with the Java 1.4 Logger class
     *
*/

    
public Server(Logger logger, Level logLevel, int maxConnections) 
    
this(maxConnections);
        setLogger(logger, logLevel);
        log(
"Starting server");
    }


    
/**
     * This constructor supports no logging
     *
*/

    
public Server(int maxConnections) {
        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;
    }


    
/** 
     * Set the current Logger and logging level. Pass null to turn logging off.
     *
*/

    
public synchronized void setLogger(Logger logger, Level level) {
    
this.logger = logger;
    
this.logLevel = level;
    }


    
/** Write the specified string to the log */
    
protected synchronized void log(String s) 
    
if (logger != null) logger.log(logLevel, 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 == nullreturn;
        
// 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(5000);
            
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. ");
        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 + " ");
    }

    
    
// Display the current connection limit
    out.print("MAX CONNECTIONS: " + maxConnections + " ");

    
// 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() 
+ " ");
    }

    }


    
/**
     * 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() + " ");
            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. ");
            out.print(
"Enter lines.  End with a '.' on a line by itself. ");
            
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(
" ");
            }

            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 ");
            out.print(
"Content-Type: text/plain ");
            String line;
            
while((line = in.readLine()) != null{
                
if (line.length() == 0break;
                out.print(line 
+ " ");
            }

            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() + " ");
            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. ");
                    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 == nullbreak;   // 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 ");       // Say so
                            authorized = true;         // Grant authorization
                        }

                        
else out.print("INVALID PASSWORD "); 
                    }

                    
else if (command.equals("add")) {  // Add Service command
                        
// Check whether password has been given
                        if (!authorized) out.print("PASSWORD REQUIRED "); 
                        
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 ");    // acknowledge
                        }

                    }

                    
else if (command.equals("remove")) // Remove service
                        if (!authorized) out.print("PASSWORD REQUIRED ");
                        
else {
                            
int port = Integer.parseInt(t.nextToken()); 
                            server.removeService(port); 
// remove the service
                            out.print("SERVICE REMOVED "); // acknowledge
                        }

                    }

                    
else if (command.equals("max")) // Set connection limit
                        if (!authorized) out.print("PASSWORD REQUIRED ");
                        
else {
                            
int max = Integer.parseInt(t.nextToken()); 
                            server.setMaxConnections(max); 
                            out.print(
"MAX CONNECTIONS CHANGED ");
                        }

                    }

                    
else if (command.equals("status")) // Status Display
                        if (!authorized) out.print("PASSWORD REQUIRED ");
            
else server.displayStatus(out);
                    }

                    
else if (command.equals("help")) {  // Help command
                        
// Display command syntax.  Password not required
                        out.print("COMMANDS: " + 
                  
" password <password> " +
                  
" add <service> <port> " +
                  
" remove <port> " +
                  
" max <max-connections> " +
                  
" status " +
                  
" help " + 
                  
" quit ");
                    }

                    
else if (command.equals("quit")) break// Quit command.
                    else out.print("UNRECOGNIZED COMMAND "); // 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: " +
                  e 
+ " ");
                }

            }

            
// 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();
        }
    
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值