网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  一个socket服务器样板程     
  文章作者:未知  文章来源:水木森林  
  查看:160次  录入:管理员--2007-11-17  
 
  这是一个非常好的socket服务器样板程序,这个socket服务器可以为你建立指定的监听端口、客户端请求响应机制等一些服务器所具备的基本框架

/*
* 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.");
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() == 0) break;
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 == 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"); // say so
authorized = true; // grant authorization
}
else out.print("invalid password"); // otherwise fail
}
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 " +
" add " +
" remove " +
" max " +
" 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();
}
}
}
 
 
上一篇: 一个socket服务的例子! 请高手指点无法捕捉的输出如何修改?    下一篇: 一个反射的简单例子
  相关文档
java常见缩略词及英文对照 11-17
用jaas 实现in struts web app(一) 11-17
java手机游戏编程之midp图形设计篇 11-17
秉承java思路 开发易于移植的j2me游戏 11-16
使用的des对称加密 11-16
java高级日期概念二 11-17
ejb的编程规则之session bean 11-16
用swing制作欢迎屏幕 11-17
javascript实现的java里的map对象 11-17
spring aop在dwr安全上的应用 11-17
事件监听器: 将javabeans接通起来的方法 11-17
想动就动 java也可以动态灵活 11-17
j2ee design patterns 11-17
java se 6 新特性: http 增强 11-17
log4j和jdbmonitor的比较 11-17
高级:cookie,httpsession类使用概述 01-14
apache cxf2.0发布并通过jax-ws2.0 tck 11-17
用jaas 实现in struts web app(二) 11-17
hibernate3.x过滤器的高级应用 11-17
mini java编译器(六) 11-17
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
技术电话:13616026886
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息