snmp4j的agent开发
来源:互联网 发布:126 smtp ssl 端口 编辑:程序博客网 时间:2024/04/28 22:44
由mib文件生成的HelloMib.java类,mib文件在运行中不会用到的。
import org.snmp4j.smi.*;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.agent.*;
import org.snmp4j.agent.mo.*;
import org.snmp4j.agent.mo.snmp.*;
import org.snmp4j.agent.mo.snmp.smi.*;
import org.snmp4j.agent.request.*;
import org.snmp4j.log.LogFactory;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.agent.mo.snmp.tc.*;
//--AgentGen BEGIN=_IMPORT
//--AgentGen END
public class HelloMib
//--AgentGen BEGIN=_EXTENDS
//--AgentGen END
implements MOGroup
//--AgentGen BEGIN=_IMPLEMENTS
//--AgentGen END
{
private static final LogAdapter LOGGER =
LogFactory.getLogger(HelloMib.class);
//--AgentGen BEGIN=_STATIC
//--AgentGen END
// Factory
private MOFactory moFactory =
DefaultMOFactory.getInstance();
// Constants
/**
* OID of this MIB module for usage which can be
* used for its identification.
*/
public static final OID oidHelloMib =
new OID(new int[] { });
public static final OID oidSysDescr =
new OID(new int[] { 1,3,6,1,2,1,4,1,1949,1,0 });
public static final OID oidSysTest =
new OID(new int[] { 1,3,6,1,2,1,4,1,1949,2,0 });
// Enumerations
// TextualConventions
// Scalars
private MOScalar sysDescr;
private MOScalar sysTest;
// Tables
//--AgentGen BEGIN=_MEMBERS
//--AgentGen END
/**
* Constructs a HelloMib instance without actually creating its
* <code>ManagedObject</code> instances. This has to be done in a
* sub-class constructor or after construction by calling
* {@link #createMO(MOFactory moFactory)}.
*/
protected HelloMib() {
//--AgentGen BEGIN=_DEFAULTCONSTRUCTOR
//--AgentGen END
}
/**
* Constructs a HelloMib instance and actually creates its
* <code>ManagedObject</code> instances using the supplied
* <code>MOFactory</code> (by calling
* {@link #createMO(MOFactory moFactory)}).
* @param moFactory
* the <code>MOFactory</code> to be used to create the
* managed objects for this module.
*/
public HelloMib(MOFactory moFactory) {
createMO(moFactory);
//--AgentGen BEGIN=_FACTORYCONSTRUCTOR
//--AgentGen END
}
//--AgentGen BEGIN=_CONSTRUCTORS
//--AgentGen END
/**
* Create the ManagedObjects defined for this MIB module
* using the specified {@link MOFactory}.
* @param moFactory
* the <code>MOFactory</code> instance to use for object
* creation.
*/
protected void createMO(MOFactory moFactory) {
addTCsToFactory(moFactory);
sysDescr =
moFactory.createScalar(oidSysDescr,
moFactory.createAccess(MOAccessImpl.ACCESSIBLE_FOR_READ_WRITE),
new OctetString("2222222222222"));
sysTest =
moFactory.createScalar(oidSysTest,
moFactory.createAccess(MOAccessImpl.ACCESSIBLE_FOR_READ_WRITE),
new OctetString("test"));
}
public MOScalar getSysDescr() {
return sysDescr;
}
public MOScalar getSysTest() {
return sysTest;
}
public void registerMOs(MOServer server, OctetString context)
throws DuplicateRegistrationException
{
// Scalar Objects
server.register(this.sysDescr, context);
server.register(this.sysTest, context);
//--AgentGen BEGIN=_registerMOs
//--AgentGen END
}
public void unregisterMOs(MOServer server, OctetString context) {
// Scalar Objects
server.unregister(this.sysDescr, context);
server.unregister(this.sysTest, context);
//--AgentGen BEGIN=_unregisterMOs
//--AgentGen END
}
// Notifications
// Scalars
// Value Validators
// Rows and Factories
//--AgentGen BEGIN=_METHODS
//--AgentGen END
// Textual Definitions of MIB module HelloMib
protected void addTCsToFactory(MOFactory moFactory) {
}
//--AgentGen BEGIN=_TC_CLASSES_IMPORTED_MODULES_BEGIN
//--AgentGen END
// Textual Definitions of other MIB modules
public void addImportedTCsToFactory(MOFactory moFactory) {
}
//--AgentGen BEGIN=_TC_CLASSES_IMPORTED_MODULES_END
//--AgentGen END
//--AgentGen BEGIN=_CLASSES
//--AgentGen END
//--AgentGen BEGIN=_END
//--AgentGen END
}
编写module类
import org.snmp4j.agent.mo.*;
import org.snmp4j.log.LogFactory;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.agent.MOGroup;
import org.snmp4j.agent.MOServer;
import org.snmp4j.agent.DuplicateRegistrationException;
import org.snmp4j.smi.OctetString;
//--AgentGen BEGIN=_IMPORT
//--AgentGen END
public class HelloModules implements MOGroup {
private static final LogAdapter LOGGER =
LogFactory.getLogger(HelloModules.class);
private HelloMib helloMib;
private MOFactory factory;
//--AgentGen BEGIN=_MEMBERS
//--AgentGen END
public HelloModules() {
helloMib = new HelloMib();
//--AgentGen BEGIN=_DEFAULTCONSTRUCTOR
//--AgentGen END
}
public HelloModules(MOFactory factory) {
helloMib = new HelloMib(factory);
//--AgentGen BEGIN=_CONSTRUCTOR
//--AgentGen END
}
public void registerMOs(MOServer server, OctetString context)
throws DuplicateRegistrationException
{
helloMib.registerMOs(server, context);
//--AgentGen BEGIN=_registerMOs
//--AgentGen END
}
public void unregisterMOs(MOServer server, OctetString context) {
helloMib.unregisterMOs(server, context);
//--AgentGen BEGIN=_unregisterMOs
//--AgentGen END
}
public HelloMib getSnmp4jDemoMib() {
return helloMib;
}
//--AgentGen BEGIN=_METHODS
//--AgentGen END
//--AgentGen BEGIN=_CLASSES
//--AgentGen END
//--AgentGen BEGIN=_END
//--AgentGen END
}
将HelloModules加到代理类SampleAgent 中
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.snmp4j.MessageDispatcher;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.TransportMapping;
import org.snmp4j.agent.AgentConfigManager;
import org.snmp4j.agent.DefaultMOContextScope;
import org.snmp4j.agent.DefaultMOQuery;
import org.snmp4j.agent.DefaultMOServer;
import org.snmp4j.agent.DuplicateRegistrationException;
import org.snmp4j.agent.MOQuery;
import org.snmp4j.agent.MOScope;
import org.snmp4j.agent.MOServer;
import org.snmp4j.agent.ManagedObject;
import org.snmp4j.agent.cfg.EngineBootsCounterFile;
import org.snmp4j.agent.io.DefaultMOPersistenceProvider;
import org.snmp4j.agent.io.MOInput;
import org.snmp4j.agent.io.MOInputFactory;
import org.snmp4j.agent.io.prop.PropertyMOInput;
import org.snmp4j.agent.mo.DefaultMOFactory;
import org.snmp4j.agent.mo.MOAccessImpl;
import org.snmp4j.agent.mo.MOFactory;
import org.snmp4j.agent.mo.MOMutableTableRow;
import org.snmp4j.agent.mo.MOScalar;
import org.snmp4j.agent.mo.MOTableRowEvent;
import org.snmp4j.agent.mo.MOTableRowListener;
import org.snmp4j.agent.mo.snmp.TimeStamp;
import org.snmp4j.agent.mo.util.VariableProvider;
import org.snmp4j.agent.request.Request;
import org.snmp4j.agent.request.RequestStatus;
import org.snmp4j.agent.request.SubRequest;
import org.snmp4j.agent.request.SubRequestIterator;
import org.snmp4j.log.JavaLogFactory;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.Counter32;
import org.snmp4j.smi.Gauge32;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.IpAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.TransportMappings;
import org.snmp4j.util.ArgumentParser;
import org.snmp4j.util.ThreadPool;
/**
* The SampleAgent uses an {@link AgentConfigManager} instance to create a
* minimal SNMP agent using the configuration defined by
* <code>SampleAgentConfig.properties</code> in this package. That properties
* file defines the initial content of the registered MIB objects of this agent
* which may differ from the hard coded defaults.
* <p>
* In order to add a new MIB object, call <code>server.register(..)</code> or
* replace the <code>Modules.java</code> file in this package by the
* <code>Modules.java</code> generated by AgenPro for your MIB module(s).
* <p>
* The agent uses the Java logging framework to log messages.
*
* @author Frank Fock
* @version 1.3.2
*/
public class SampleAgent implements VariableProvider {
static {
LogFactory.setLogFactory(new JavaLogFactory());
}
private LogAdapter logger = LogFactory.getLogger(SampleAgent.class);
protected AgentConfigManager agent;
protected MOServer server;
private String configFile;
private File bootCounterFile;
// supported MIBs
protected HelloModules modules;
protected Properties tableSizeLimits;
public SampleAgent(Map args) {
configFile = (String)((List)args.get("c")).get(0);
bootCounterFile = new File((String)((List)args.get("bc")).get(0));
server = new DefaultMOServer();
MOServer[] moServers = new MOServer[] { server };
InputStream configInputStream =
SampleAgent.class.getResourceAsStream("SampleAgentConfig.properties");
if (args.containsKey("cfg")) {
try {
configInputStream =
new FileInputStream((String) ArgumentParser.getValue(args, "cfg", 0));
}
catch (FileNotFoundException ex1) {
ex1.printStackTrace();
}
}
final Properties props = new Properties();
try {
props.load(configInputStream);
}
catch (IOException ex) {
ex.printStackTrace();
}
MOInputFactory configurationFactory = new MOInputFactory() {
public MOInput createMOInput() {
return new PropertyMOInput(props, SampleAgent.this);
}
};
InputStream tableSizeLimitsInputStream =
SampleAgent.class.getResourceAsStream("SampleAgentTableSizeLimits.properties");
if (args.containsKey("ts")) {
try {
tableSizeLimitsInputStream =
new FileInputStream((String) ArgumentParser.getValue(args, "ts", 0));
}
catch (FileNotFoundException ex1) {
ex1.printStackTrace();
}
}
tableSizeLimits = new Properties();
try {
tableSizeLimits.load(tableSizeLimitsInputStream);
}
catch (IOException ex) {
ex.printStackTrace();
}
MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
addListenAddresses(messageDispatcher, (List)args.get("address"));
agent = new AgentConfigManager(new OctetString(MPv3.createLocalEngineID()),
messageDispatcher,
null,
moServers,
ThreadPool.create("SampleAgent", 3),
configurationFactory,
new DefaultMOPersistenceProvider(moServers,
configFile),
new EngineBootsCounterFile(bootCounterFile));
}
protected void addListenAddresses(MessageDispatcher md, List addresses) {
for (Iterator it = addresses.iterator(); it.hasNext();) {
Address address = GenericAddress.parse((String)it.next());
TransportMapping tm =
TransportMappings.getInstance().createTransportMapping(address);
if (tm != null) {
md.addTransportMapping(tm);
}
else {
logger.warn("No transport mapping available for address '"+
address+"'.");
}
}
}
public void run() {
// initialize agent before registering our own modules
agent.initialize();
// this requires sysUpTime to be available.
registerMIBs();
// add proxy forwarder
agent.setupProxyForwarder();
// apply table size limits
agent.setTableSizeLimits(tableSizeLimits);
// now continue agent setup and launch it.
agent.run();
}
/**
* Get the {@link MOFactory} that creates the various MOs (MIB Objects).
* @return
* a {@link DefaultMOFactory} instance by default.
* @since 1.3.2
*/
protected MOFactory getFactory() {
return DefaultMOFactory.getInstance();
}
/**
* Register your own MIB modules in the specified context of the agent.
* The {@link MOFactory} provided to the <code>Modules</code> constructor
* is returned by {@link #getFactory()}.
*/
protected void registerMIBs()
{
try {
modules=new HelloModules(getFactory());
modules.registerMOs(server, null);
// Some alternatives
// Register a scalar with your OID in your enterprise subtree:
/* MOScalar myScalar = new MOScalar(new OID(new int[] { 1,3,6,1,4,1,1,0 }),
MOAccessImpl.ACCESS_READ_WRITE,
new OctetString("myText"));
server.register(myScalar, null);*/
// Register a table with a string index and a single integer payload column
// a row status column to
/*DefaultMOTable myTable =
new DefaultMOTable(new OID("<tableEntryOID>"),
new MOTableIndex(new MOTableSubIndex[] {
new MOTableSubIndex(new OID("<indexObjectClassOID>"),
SMIConstants.SYNTAX_OCTET_STRING, 1, 16) },
true),
new MOMutableColumn[] {
new MOMutableColumn(1, SMIConstants.SYNTAX_INTEGER32,
MOAccessImpl.ACCESS_READ_CREATE,
new Integer32(10), true),
new RowStatus(2)
});
server.register(myTable, null);*/
}
catch (DuplicateRegistrationException drex) {
logger.error("Duplicate registration: "+drex.getMessage()+"."+
" MIB object registration may be incomplete!", drex);
}
}
public Variable getVariable(String name) {
OID oid;
OctetString context = null;
int pos = name.indexOf(':');
if (pos >= 0) {
context = new OctetString(name.substring(0, pos));
oid = new OID(name.substring(pos+1, name.length()));
}
else {
oid = new OID(name);
}
final DefaultMOContextScope scope =
new DefaultMOContextScope(context, oid, true, oid, true);
MOQuery query = new DefaultMOQuery(scope, false, this);
ManagedObject mo = server.lookup(query);
if (mo != null) {
final VariableBinding vb = new VariableBinding(oid);
final RequestStatus status = new RequestStatus();
SubRequest req = new SubRequest() {
private boolean completed;
private MOQuery query;
public boolean hasError() {
return false;
}
public void setErrorStatus(int errorStatus) {
status.setErrorStatus(errorStatus);
}
public int getErrorStatus() {
return status.getErrorStatus();
}
public RequestStatus getStatus() {
return status;
}
public MOScope getScope() {
return scope;
}
public VariableBinding getVariableBinding() {
return vb;
}
public Request getRequest() {
return null;
}
public Object getUndoValue() {
return null;
}
public void setUndoValue(Object undoInformation) {
}
public void completed() {
completed = true;
}
public boolean isComplete() {
return completed;
}
public void setTargetMO(ManagedObject managedObject) {
}
public ManagedObject getTargetMO() {
return null;
}
public int getIndex() {
return 0;
}
public void setQuery(MOQuery query) {
this.query = query;
}
public MOQuery getQuery() {
return query;
}
public SubRequestIterator repetitions() {
return null;
}
public void updateNextRepetition() {
}
public Object getUserObject() {
return null;
}
public void setUserObject(Object userObject) {
}
};
mo.get(req);
return vb.getVariable();
}
return null;
}
class DemoTableRowListener implements MOTableRowListener {
public void rowChanged(MOTableRowEvent event) {
if ((event.getType() == MOTableRowEvent.CREATE) ||
(event.getType() == MOTableRowEvent.UPDATED)) {
// ignore
return;
}
// update counter
Counter32 counter = (Counter32)
event.getRow().getValue(Snmp4jDemoMib.idxSnmp4jDemoEntryCol3);
if (counter == null) {
counter = new Counter32(0);
((MOMutableTableRow)
event.getRow()).setValue(Snmp4jDemoMib.idxSnmp4jDemoEntryCol3,
counter);
}
counter.increment();
// update timestamp
TimeStamp timestamp = (TimeStamp)
event.getTable().getColumn(Snmp4jDemoMib.idxSnmp4jDemoEntryCol4);
timestamp.update((MOMutableTableRow)event.getRow(),
Snmp4jDemoMib.idxSnmp4jDemoEntryCol4);
// fire notification
Integer32 type =
new Integer32(Snmp4jDemoMib.Snmp4jDemoTableRowModificationEnum.updated);
switch (event.getType()) {
case MOTableRowEvent.ADD:
type.setValue(Snmp4jDemoMib.Snmp4jDemoTableRowModificationEnum.created);
break;
case MOTableRowEvent.DELETE:
type.setValue(Snmp4jDemoMib.Snmp4jDemoTableRowModificationEnum.deleted);
break;
}
VariableBinding[] payload = new VariableBinding[2];
OID table = event.getTable().getOID();
OID updateCount = new OID(table);
updateCount.append(Snmp4jDemoMib.colSnmp4jDemoEntryCol3);
updateCount.append(event.getRow().getIndex());
OID modifyType = new OID(table);
modifyType.append(Snmp4jDemoMib.colSnmp4jDemoTableRowModification);
modifyType.append(event.getRow().getIndex());
payload[0] = new VariableBinding(updateCount, counter);
payload[1] = new VariableBinding(modifyType, type);
//modules.getSnmp4jDemoMib().snmp4jDemoEvent(
// agent.getNotificationOriginator(), new OctetString(), payload);
}
}
/**
* Runs a sample agent with a default configuration defined by
* <code>SampleAgentConfig.properties</code>. A sample command line is:
* <pre>
* -c SampleAgent.cfg -bc SampleAgent.bc udp:127.0.0.1/4700 tcp:127.0.0.1/4700
* </pre>
*
* @param args
* the command line arguments defining at least the listen addresses.
* The format is <code>-c[s{=SampleAgent.cfg}] -bc[s{=SampleAgent.bc}]
* +ts[s] +cfg[s] #address[s<(udp|tcp):.*[/[0-9]+]?>] ..</code>.
* For the format description see {@link ArgumentParser}.
*/
public static void main(String[] args) {
ArgumentParser parser =
new ArgumentParser("-c[s{=SampleAgent.cfg}] -bc[s{=SampleAgent.bc}] "+
"+ts[s] +cfg[s]",
"#address[s<(udp|tcp):.*[/[0-9]+]?>] ..");
Map commandLineParameters = null;
try {
args=new String[1];
args[0]="udp:127.0.0.1/4700";
commandLineParameters = parser.parse(args);
SampleAgent sampleAgent = new SampleAgent(commandLineParameters);
// Add all available security protocols (e.g. SHA,MD5,DES,AES,3DES,..)
SecurityProtocols.getInstance().addDefaultProtocols();
// configure system group:
// Set system description:
// sampleAgent.agent.getSysDescr().setValue("My system description".getBytes());
// Set system OID (= OID of the AGENT-CAPABILITIES statement describing
// the implemented MIB objects of this agent:
// sampleAgent.agent.getSysOID().setValue("1.3.1.6.1.4.1....");
// Set the system services
//sampleAgent.agent.getSysServices().setValue(72);
sampleAgent.run();
}
catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
}
运行SampleAgent主函数,则agent端就算运行起来了,根据需要再进行manager的代码编写。
import java.io.IOException;
import java.util.Vector;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
public class SnmpUtil {
private Snmp snmp = null;
private Address targetAddress = null;
public void initComm() throws IOException {
// 设置Agent方的IP和端口
targetAddress = GenericAddress.parse("udp:127.0.0.1/4700");
TransportMapping transport = new DefaultUdpTransportMapping();
snmp = new Snmp(transport);
transport.listen();
}
public ResponseEvent sendPDU(PDU pdu) throws IOException {
// 设置 target
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
// 通信不成功时的重试次数
target.setRetries(2);
// 超时时间
target.setTimeout(1500);
target.setVersion(SnmpConstants.version1);
// 向Agent发送PDU,并返回Response
return snmp.send(pdu, target);
}
public void setPDU() throws IOException {
// set PDU
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,4,1,1,0}), new OctetString("8899")));
pdu.setType(PDU.SET);
sendPDU(pdu);
}
public void getPDU() throws IOException {
// get PDU
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,4,1,1,0})));// pcName
pdu.setType(PDU.GET);
readResponse(sendPDU(pdu));
}
public void readResponse(ResponseEvent respEvnt) {
// 解析Response
System.out.println("----------解析Response-------------");
if (respEvnt != null && respEvnt.getResponse() != null) {
Vector<VariableBinding> recVBs = respEvnt.getResponse()
.getVariableBindings();
for (int i = 0; i < recVBs.size(); i++) {
VariableBinding recVB = recVBs.elementAt(i);
System.out
.println(recVB.getOid() + " : " + recVB.getVariable());
}
}
}
public void sendPDU() throws IOException {
// 设置 target
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
// 通信不成功时的重试次数
target.setRetries(2);
// 超时时间
target.setTimeout(1500);
target.setVersion(SnmpConstants.version1);
// 创建 PDU
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(new int[] { 1,3,6,1,2,1,4,1,1949,1,0 })));
// MIB的访问方式
pdu.setType(PDU.GET);
// 向Agent发送PDU,并接收Response
ResponseEvent respEvnt = snmp.send(pdu, target);
// 解析Response
if (respEvnt != null && respEvnt.getResponse() != null) {
Vector<VariableBinding> recVBs = respEvnt.getResponse()
.getVariableBindings();
for (int i = 0; i < recVBs.size(); i++) {
VariableBinding recVB = recVBs.elementAt(i);
System.out.println(recVB.getOid() + " = " + recVB.getVariable());
}
}
}
public static void main(String[] args) {
try {
SnmpUtil util = new SnmpUtil();
util.initComm();
util.sendPDU();
// util.setPDU();
//util.getPDU();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行SnmpUtil可看到运行结果:
1.3.6.1.2.1.4.1.1949.1.0 = 2222222222222
- snmp4j的agent开发
- snmp4j的agent开发
- snmp4j的简单实现
- snmp4j 的简单使用
- SNMP4J开发trap监听实例
- AGENT开发
- SNMP4J
- SNMP4J
- SNMP4J
- 用snmp4j开发网管应用(二) -- 使用snmp4j
- 网管SNMP Agent的快速开发
- 网管SNMP Agent的快速开发
- 网管SNMP Agent的快速开发
- [Web开发] IE8的User-Agent 字符串
- 网管SNMP Agent的快速开发
- 网管SNMP Agent的快速开发[转]
- 网管SNMP Agent的快速开发
- 开发兼容Win7的Ms Agent程序
- SAP需要经常监控的目录
- C字符数组赋值
- 随心所欲
- c# 在TextBox里实现右键单击移动光标位置(让右键单击和左键单击有一样的效果)
- ipod live stream
- snmp4j的agent开发
- 互动网计算机频道图书7日销售排行(08.05-08.11)
- poj1012 Joseph题解
- 一个php小问题
- 水晶报表基础入门——2.水晶报表命名空间下包含的类
- PPT
- 深入理解Servlet/JSP之Cookie和Session原理
- 亿天网络开通了
- C++基本语法4--C++程序设计教程/钱能主编--清华大学出版社