package book.net;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* 这个类实现了一个灵活的、支持多线程的服务器的通用框架。
* 它能够侦听任何端口,当收到来自某个端口的连接请求时,
* 将连接的输入和输出传递给特定的服务对象。由服务对象处理请求。
* 支持一定数量的并发访问,支持日志功能,将日志写到输出流中。
**/
public class GeneralServer {
// 服务器上行的分割符
// 出于java的安全限制,System.getProperty("line.seperator")是不能够直接取得的
// 通过下面的方法获取
public static final String LINE_SEPERATOR = (String) java.security.AccessController
.doPrivileged(new sun.security.action.GetPropertyAction(
"line.separator"));
// 帮助信息,指示启动服务器必须带有参数,
// 参数包括:
// (1)服务器启动的服务的类名、服务对应的端口号
// (2)如果需要对服务器进行控制,则需要指定控制密码和端口。
public static final String HELP_MESSAGE = "Usage: java book.net.GeneralServer "
+ "[-control <password> <port>] "
+ "[<servicename> <port> ... ]";
// 保存侦听器及其侦听端口的映射
Map services;
// 保存当前的连接信息
Set connections;
// 支持的最大并发连接数
int maxConnections;
// 管理服务器启动的所有线程
ThreadGroup threadGroup;
// 日志消息的输出流
PrintWriter logStream;
/**
* 构造方法
* 指定日志消息输出流和最大并发连接数。
**/
public GeneralServer(OutputStream logStream, int maxConnections) {
// 初始化各实例变量
this.setLogStream(logStream);
this.log("Starting server");
// 创建一个线程组,所有启动的线程都在该组内
this.threadGroup = new ThreadGroup(GeneralServer.class.getName());
this.maxConnections = maxConnections;
this.services = new HashMap();
this.connections = new HashSet(maxConnections);
}
/**
* 设置日志消息输出流,允许参数为null
**/
public synchronized void setLogStream(OutputStream out) {
if (out != null){
this.logStream = new PrintWriter(out);
} else {
this.logStream = null;
}
}
/**
* 写字符串类型的日志信息到日志输出流。
*/
protected synchronized void log(String s) {
if (this.logStream != null) {
this.logStream.println("[" + new Date() + "] " + s);
this.logStream.flush();
}
}
/**
* 写对象类型的日志信息到日志输出流
*/
protected void log(Object o) {
this.log(o.toString());
}
/**
* 服务器启动一个新服务,该服务对象运行在指定的端口上。
* @param service 待启动的服务对象
* @param port 服务对象使用的端口
* @throws IOException
*/
public synchronized void addService(Service service, int port)
throws IOException {
// 首先判断该端口是否已经被服务器使用了
Integer key = new Integer(port);
if (this.services.get(key) != null)
throw new IllegalArgumentException("Port " + port
+ " already in use.");
// 为服务和端口创建一个侦听器,侦听连接请求
Listener listener = new Listener(threadGroup, port, service);
// 将端口和侦听器保存
this.services.put(key, listener);
// 写日志
this.log("Starting service " + service.getClass().getName() + " on port "
+ port);
// 启动侦听器
listener.start();
}
/**
* 服务器停止一个服务,它不会中止任何已经接受了的连接,
* 但是会使服务器停止接受关于该端口的连接请求
* @param port 待停止服务的端口
*/
public synchronized void removeService(int port) {
// 找到该端口上的侦听器
Integer key = new Integer(port);
final Listener listener = (Listener) services.get(key);
// 将侦听器停止
if (listener == null) {
return;
}
listener.pleaseStop();
// 将端口上的服务去掉
this.services.remove(key);
// 写日志
this.log("Stopping service " + listener.service.getClass().getName()
+ " on port " + port);
}
/**
* 启动服务器的方法,需要配置参数。
*/
public static void main(String[] args) {
try {
// 参数数目必须大于等于2。
if (args.length < 2) // Check number of arguments
throw new IllegalArgumentException("Must specify a service");
// 本例使用标准的输出流当作日志信息输出流,同时连接数最大为10
GeneralServer server = new GeneralServer(System.out, 10);
// 解析参数
int i = 0;
while (i < args.length) {
// 处理-control参数
if (args[i].equals("-control")) {
i++;
// 获取控制的密码
String password = args[i++];
// 获取控制的端口
int port = Integer.parseInt(args[i++]);
// 加载控制服务实例,在端口上工作。
server.addService(new Control(server, password), port);
} else {
// 处理初始启动的服务参数,并动态加载服务实例
// 获取服务的类名
String serviceName = args[i++];
// 根据服务类名生成实例
Class serviceClass = Class.forName(serviceName);
Service service = (Service) serviceClass.newInstance();
// 获取端口
int port = Integer.parseInt(args[i++]);
// 启动服务
server.addService(service, port);
}
}
} catch (Exception e) {
// 参数错误
System.err.println("Server: " + e);
System.err.println(HELP_MESSAGE);
System.exit(1);
}
}
/**
* 增加一个连接。
* 当侦听器收到客户端的连接请求时,会调用该方法。
* 这里会创建一个连接对象,并保存,如果连接数已满,则关闭连接。
* @param s 连接的客户端socket
* @param service 连接请求的服务
*/
protected synchronized void addConnection(Socket s, Service service) {
// 判断连接数是否已满
if (this.connections.size() >= this.maxConnections) {
try {
// 拒绝客户端
PrintWriter out = new PrintWriter(s.getOutputStream());
out.print("Connection refused; "
+ "the server is busy; please try again later." + LINE_SEPERATOR);
out.flush();
// 关闭socket连接
s.close();
// 写日志
this.log("Connection refused to "
+ s.getInetAddress().getHostAddress() + ":"
+ s.getPort() + ": max connections reached.");
} catch (IOException e) {
this.log(e);
}
} else {
// 如果连接数没满,则接受连接请求
// 创建一个连接Connection对象
Connection c = new Connection(s, service);
// 保存并写日志
this.connections.add(c);
this.log("Connected to " + s.getInetAddress().getHostAddress() + ":"
+ s.getPort() + " on port " + s.getLocalPort()
+ " for service " + service.getClass().getName());
// 启动连接线程
c.start();
}
}
/**
* 结束一个连接
* @param c
*/
protected synchronized void endConnection(Connection c) {
// 从连接列表中清除
this.connections.remove(c);
this.log("Connection to " + c.client.getInetAddress().getHostAddress() + ":"
+ c.client.getPort() + " closed.");
}
/**
* 设置服务器的并行最大访问数
* @param max
*/
public synchronized void setMaxConnections(int max) {
this.maxConnections = max;
}
/**
* 显示服务器状态,有利于调试和控制服务器
* @param out 状态信息的输出流
*/
public synchronized void displayStatus(PrintWriter out) {
// 显示服务器提供的所有服务的信息
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 + LINE_SEPERATOR);
}
// 显示服务器当前连接数的限制
out.print("MAX CONNECTIONS: " + this.maxConnections + LINE_SEPERATOR);
// 显示当前所有连接的信息
Iterator conns = this.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() + LINE_SEPERATOR);
}
}
/**
* 内部类,实现侦听器,负责侦听端口的连接请求,使用了ServerSocket
* 当收到一个连接请求时,调用Server的addConnection方法,决定是否接受连接请求。
* 服务器上每个服务都有一个侦听器。
**/
public class Listener extends Thread {
// 侦听连接的socket
ServerSocket listen_socket;
// 侦听端口
int port;
//
没有合适的资源?快使用搜索试试~ 我知道了~
net.rar_获取IP
共51个文件
ini:26个
java:20个
class:5个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 138 浏览量
2022-09-22
18:40:00
上传
评论
收藏 46KB RAR 举报
温馨提示
获取IP地址和机器名 本类为支持多线程服务器框架的GeneralServer类提供了一个相关的服务Service, 使GeneralServer提供代理服务。内部类ProxyService实现了GeneralServer.Service接口
资源推荐
资源详情
资源评论
收起资源包目录
net.rar (51个子文件)
net
GeneralServer.java 18KB
ftp
client
_desktop.ini 9B
MainFrame.java 17KB
Connector.java 1KB
DownloadFileThread.java 2KB
Desktop_.ini 9B
UploadFileThread.java 3KB
_desktop.ini 9B
Desktop_.ini 9B
TelnetClient.java 3KB
ProxyServer.java 5KB
_desktop.ini 9B
GetIPAddress.java 2KB
url
_desktop.ini 9B
WebBrowser.java 16KB
GetURLInfo.java 2KB
Desktop_.ini 9B
book
_desktop.ini 9B
net
_desktop.ini 9B
TelnetClient.class 2KB
Pipe.class 840B
GetIPAddress.class 2KB
Desktop_.ini 9B
Desktop_.ini 9B
udp
_desktop.ini 9B
UDPReceive.java 2KB
Desktop_.ini 9B
UDPSend.java 3KB
http
_desktop.ini 9B
HttpServer.java 8KB
HttpClient.java 1KB
Desktop_.ini 9B
chat
Constants.java 616B
_desktop.ini 9B
ChatClient.java 9KB
ChatServer.java 10KB
Desktop_.ini 9B
Desktop_.ini 9B
simplesocket
_desktop.ini 9B
book
_desktop.ini 9B
net
_desktop.ini 9B
Desktop_.ini 9B
simplesocket
_desktop.ini 9B
ClientFrame.class 2KB
SimpleClient.class 1KB
Desktop_.ini 9B
Desktop_.ini 9B
ClientFrame.java 2KB
SimpleServer.java 2KB
SimpleClient.java 1KB
Desktop_.ini 9B
共 51 条
- 1
资源评论
朱moyimi
- 粉丝: 61
- 资源: 1万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功