computer 版 (精华区)

发信人: arbo (arbo), 信区: program
标  题: java笔记12附录 RMI教程
发信站: 听涛站 (2001年09月17日10:57:31 星期一), 站内信件

JavaTM 2 SDK,
Standard Edition,
v 1.2
----------------------------------------------------------------------------
----
RMI
Very Frequent Questions
A.1 Why do I get an exception for an unexpected hostname and/or port number 
whenn I call Naming.lookup?
A.2 Do I have to install the _Stub file in the client's CLASSPATH? I thought
 it could be downloaded.
A.3 Does RMI require me to use an HTTP server?
A.4 Why am I getting a ClassNotFoundException?
Debugging RMI programs
B.1 Will there be debugging mechanisms built into RMI?
B.2 I am having a problem debugging my program on Windows95. Any suggestions
?
B.3 Why do I get a java.lang.ClassMismatchError while running my program?
B.4 I am sending an array of remote objects and receive an ArrayStoreExcepti
on. What's going on?
B.5 I have local objects that are synchronized. When I make them remote, my 
appllication hangs. What's the problem?
B.6 I am getting a ClassNotFoundException for my stub class when I try to re
gistter a remote object in the registry. What's happening?
B.7 My server died. Can I get a trace of the server activity?
Networking
C.1 How do RMI clients contact remote RMI servers?
C.2 Why does my remote method or "callback" routine fail with a nested java.
net..UnknownHostException?
C.3 My server is using a fully-qualified domain name or IP address, so why d
o I still get an UnknownHostException?
C.4 I am using the latest release of the Java 2 SDK and I have a host that h
as mmultiple IP addresses. RMI is choosing the wrong IP address for its serv
er hostname, how do I work around this problem?
C.5 How does RMI obtain a server hostname in each of the versions of the JDK
?
C.6 Why do Naming.bind and Naming.lookup take an extraordinarily long time o
n Wiindows?
C.7 How do I use RMI on a Windows95 standalone machine, not connected to the
 nettwork?
C.8 Why do I get the exception "java.net.SocketException: Address already in
 usee" when I try to run the registry?
C.9 How can I use RMI through a firewall?
C.10 How can I make outgoing RMI calls through a local firewall?
C.11 How can I receive incoming RMI calls through a local firewall?
C.12 So what do I have to do to get RMI to operate through two firewalls?
C.13 Is it possible to replace the java-rmi.cgi script that comes with the J
DK ddistribution with a servlet?
Using RMI to achieve X (for some X)
D.1 Is there a way to get automatic notification as soon as a remote Java VM
 faiils?
D.2 From within a Java Virtual Machine, can a new Java VM be spawned on a re
motee machine?
D.3 Is it possible for a remote object to be notified when all clients disco
nnecct?
D.4 Why doesn't my server program exit when all clients disconnect?
D.5 How does the distributed garbage collector detect a client that disconne
cts?? Is it advisable to use System.exit for graceful client termination?
D.6 How can my server tell when a client crashes?
D.7 The unreferenced() method doesn't get called until ten minutes after I h
ave stopped using the remote object! How can I shorten this delay?
D.8 Why can't I get an immediate notification when a client crashes?
D.9 How do I run the rmic command in a DOS batch file?
D.10 In a remote object implementation, how can I find the host name of the 
calller of a remote method?
D.11 Does RMI handle "out" and "inout" parameters (like CORBA)?
D.12 Normally in the Java programming language, it is possible to cast an in
terfface instance to an instance of the class from which it was created and 
use the result. Why doesn't this work in RMI?
How does RMI work with X (for some X)
E.1 When will Netscape support RMI?
E.2 Can I implement remote observer/observable objects in RMI?
E.3 How is RMI related to CORBA?
Internals, resources, and performance
F.1 At what point is there a "live" connection between the client and the se
rverr and how are connections managed?
F.2 Does the Java platform replace all remote objects with their stubs durin
g a remote method invocation?
F.3 Is it possible to write a new transport layer for RMI which does not use
 socckets? As a follow-up question, how about a transport layer that uses no
n-TCP based sockets?
F.4 I notice the registry continues to use CPU resources, as if it were poll
ing rather than blocking on a select() call. Is the registry implemented by 
polling?
F.5 Is there only one socket connection between a client process and the ser
ver,, no matter how many stubs exist in that client process?
Miscellaneous
G.1 What are the licensing issues surrounding the use of RMI?
G.2 I have a single-threaded program that waits on standard input for a user
 commmand which will initiate an RMI call. However, my remote object cannot 
service this incoming remote call as the program appears to be blocke
problem?
G.3 I am copying array elements to my remote server and changing the values,
 butt the incremented values are not copied back to the client. Why?
G.4 Am I allowed to have static fields in a remote interface?
G.5 I locate the registry, but then it seems that it's not there, what's hap
peniing?
G.6 I can't find the answer to my question here, are there any other resourc
es?
Object Serialization
Why must classes implement Serializable in order to be written to an ObjectO
utpuutStream?
Which JDK 1.1 system classes are marked serializable?
I am having problems deserializing AWT components. How can I make this work?

Does object serialization support encryption?
The object serialization classes are stream oriented. How do I write objects
 to a random-access file?
When a local object is serialized and passed as a parameter in an RMI call, 
are the bytecodes for the local object's methods also passed? What about obj
ect coherency, if the remote VM application "keeps" the object handl
How can I create an ObjectInputStream from an ObjectOutputStream without a f
ile in between?
I create an object and then send it across the net using the writeObject met
hod and receive it using the readObject method. If I then change the value o
f a field in the object and send it as before, the object that the r
to be the same as the first object and does not reflect the new value of the
 fieeld. Should I be experiencing this behavior?
Are there any plans to support the serialization of thread objects?
Can I compute diff(serial(x),serial(y))?
Can I compress the serial representation of my objects using my own zip and 
unziip methods?
Can I execute methods on compressed versions of my objects, for example isem
pty((zip(serial(x)))?
If I try to serialize a font or image object and then try to reconstitute it
 in a different VM, my application dies. Why?
How do I serialize a tree of objects?
If class A does not implement Serializable but a subclass B implements Seria
lizaable, will the fields of class A be serialized when B is serialized?
----------------------------------------------------------------------------
----
RMI
A.1 Why do I get an exception for an unexpected hostname and/or port number 
whenn I call Naming.lookup?
The hostname and port number you see in the exception trace represent the ad
dresss on which the looked-up server believes it is listening. While the RMI
 server can theoretically be on any host, it is usually the same host
is running, and on a different port.
Even if the server is mistaken about its hostname or IP address (or has a ho
stnaame that simply isn't resolvable by clients), it will still export all o
f its objects using that mistaken hostname, but you will see an excep
receive one of those objects.
The hostname which you specified in Naming.lookup to locate the registry has
 no effect on the hostname which is already embedded in the remote reference
 to the server.
Usually, the mysterious hostname is the unqualified hostname of the server, 
or aa private name unknown to the client's nameservice, or (in the case of W
indows) the server's Network->Identification->Machine Name.
The appropriate workaround is to set the system property java.rmi.server.hos
tnamme when starting the server. The value of the property should be the ext
ernally reachable hostname (or IP address) of the server -- whatever
host-part in Naming.lookup is good enough.
For more detail, see the questions on callbacks and fully-qualified domain n
amess.
A.2 Do I have to install the _Stub file in the client's CLASSPATH? I thought
 it could be downloaded.
A stub class can be downloaded, if the server that is exporting the remote o
bjecct annotates the marshalled stub instance with the java.rmi.server.codeb
ase property, which indicates the location from where the stub class
the java.rmi.server.codebase property on the server exporting a remote objec
t. WWhile remote clients could set this property, they would then be limited
 to only getting remote objects from the specified codebase. You shou
will have specified a codebase that resolves to the location of your object.

When a remote object is marshalled by RMI (whether as an argument to a remot
e caall or as a return value), the codebase for the stub class is retrieved 
by RMI and used to annotate the serialized stub. When the stub is unm
to load the stub classfile using the RMIClassLoader, unless the class can al
readdy be found in the CLASSPATH or by the context classloader for the recei
ving object, such as an applet codebase.
If the _Stub class was loaded by an RMIClassLoader, then RMI already knows w
hichh codebase to use for its annotation. If the _Stub class was loaded from
 the CLASSPATH, then there is no obvious codebase, and RMI consults t
system property to find the codebase. If the system property is not set, the
n thhe stub is marshalled with a null codebase, which means that it cannot b
e used unless the client has a matching copy of the _Stub classfile i
 It is easy to forget to specify the codebase property. One way to detect th
is eerror is to start the rmiregistry separately and without access to the a
pplication classes. This will force Naming.rebind to fail if the code
For more information on the java.rmi.server.codebase property, please take a
 loook at our tutorial, Dynamic code downloading using RMI (Using the java.r
mi.server.codebase Property).
A.3 Does RMI require me to use an HTTP server?
No. You can set your java.rmi.server.codebase property to use any valid URL 
prottocol, such as file:/// or ftp://. Using an HTTP server just makes your 
life simpler by providing an automated mechanism for class file downl
to an HTTP server nor the inclination to set one up, you can use our small c
lasss file server found at ftp://ftp.javasoft.com/pub/jdk1.1/rmi/class-serve
r.zip.
A.4 Why am I getting a ClassNotFoundException?
Most likely the java.rmi.server.codebase property has not been set (or has n
ot bbeen set correctly) on a JVM that is exporting your remote object(s). Pl
ease take a look at our tutorial, Dynamic code downloading using RMI
java.rmi.server.codebase Property).
B.1 Will there be debugging mechanisms built into RMI?
RMI supports a simple call-logging facility for debugging. But there are no 
currrent plans to support a full-featured, interactive, remote debugger.
B.2 I am having a problem debugging my program on Windows95. Any suggestions
?
The javaw command throws away output to stdout and stderr, so for debugging 
purpposes it is better to run the java command in a separate window so that 
you can see reported errors. To do this, execute a command like the f
        start java EchoImpl
It is advised not to use the javaw command during development. To watch the 
servver activity, start the server with -Djava.rmi.server.logCalls=true.
B.3 Why do I get a java.lang.ClassMismatchError while running my program?
You probably modified one or more classes that were being used by RMI progra
ms wwhile your program was running. Try restarting all RMI applications (inc
luding java.rmi.registry.RegistryImpl). This should clear things up.
B.4 I am sending an array of remote objects and receive an ArrayStoreExcepti
on. What's going on?
RMI replaces the remote objects with the stub and therefore the type of the 
arraay must be that of the interface. The code would look like:
   FooRemote[] f = new FooRemote[10];
   for (int i = 0; i < f.length; i++) {
      f[i] = new FooRemoteImpl();
   }
Now RMI can put the stub into each cell of the array without an exception on
 thee remote call.
B.5 I have local objects that are synchronized. When I make them remote, my 
appllication hangs. What's the problem?
What you encountered was distributed deadlock. In the local VM case, the VM 
can tell that the calling object "A" owns the lock and will allow the call b
ack to "A" to proceed. In the distributed case, no such determinatio
deadlock.
Distributed objects behave differently than local objects. If you simply reu
se aa local implementation without handling locking and failure, you will pr
obably get unpredictable results.
B.6 I am getting a ClassNotFoundException for my stub class when I try to re
gistter a remote object in the registry. What's happening?
When you make a call to the registry to bind an object, the registry actuall
y biinds a reference to the stub for the remote object. In order to instanti
ate a stub object, the registry VM needs to be able to load its class
case the server VM) that sends the serialized forms of a stub in a remote me
thodd call to the registry is responsible for annotating the stub with the l
ocation from which its classes can be downloaded. If stubs are not an
a ClassNotFoundException when it tries to instantiate the stub.
To annotate classes properly, the server needs needs to set the value of the
 javva.rmi.server.codebase property value to the location(s) of the stub cla
sses. RMI will automatically annotate the serialized form of outgoing
of the java.rmi.server.codebase property.
NOTE: It is possible (and in a small number of environments appropriate) to 
enabble the rmiregistry to unmarshal stub objects by placing all relevant st
ub class files in the CLASSPATH of the rmiregistry. However, the rmir
download stub classes. If stub classes are available locally, it will use th
ose classes. Using the rmiregistry's CLASSPATH for stub deployment requires 
that all VMs that reference a stub instance obtained from that regis
installed locally (in the VM's CLASSPATH).
For example, if the registry loads stub classes from its CLASSPATH, when the
 reggistry sends serialized stub objects to other VMs, those serialized obje
cts will be annotated with the value of the registry's java.rmi.serve
almost always be null). If the VMs receiving serialized stub objects from th
e reegistry do not have the class files for those stubs installed locally th
en those VMs are likely to throw a ClassNotFoundException.
Instead, if classes are downloaded dynamically from a server VM's java.rmi.s
erveer.codebase annotation, only the server VM needs to have the stub classe
s in its CLASSPATH. With this approach, application deployment is sim
introduce new stub versions into a running distributed system.
For more information on dynamic code downloading in RMI, please see the tuto
riall, Dynamic code downloading using RMI (Using the java.rmi.server.codebas
e).
B.7 My server died. Can I get a trace of the server activity?
To get a trace of the server activity, start the server as follows:
    java -Djava.rmi.server.logCalls=true YourServerimpl
where YourServerImpl is the name of your server. If your server has hung, yo
u caan get a monitor dump and thread dump by doing a ctrl-\ on solaris and a
 ctrl-break on Windows.
C.1 How do RMI clients contact remote RMI servers?
For an RMI client to contact a remote RMI server, the client must first hold
 a rreference to the server. The Naming.lookup method call is the most commo
n mechanism by which clients initially obtain references to remote se
obtained by other means, for example: all remote method calls can return rem
ote references. This is what Naming.lookup does; it uses a well-known stub t
o make a remote method call to the rmiregistry, which sends back the
requested by the lookup method.
Every remote reference contains a server hostname and port number that allow
 cliients to locate the virtual machine that is serving a particular remote 
object. Once an RMI client has a remote reference, the client will us
in the reference to open a socket connection to the remote server.
Please note that with RMI the terms client and server can refer to the same 
Javaa program. A Java program that acts as an RMI server contains an exporte
d remote object. An RMI client is a program that invokes one or more
another Java Virtual Machine (JVM). If a JVM performs both of these function
s, iit may be referred to as an RMI client and an RMI server.
C.2 Why does my remote method or "callback" routine fail with a nested java.
net..UnknownHostException?
In many versions of the JDK (all versions of the JDK except in 1.1, and the 
lateest releases), RMI may default to using an unresolvable server hostname 
(for example: unqualified names, WINS names, or unqualified DHCP name
remote method using a reference that contains an unresolvable server hostnam
e, tthe client will throw an UnknownHostException.
In order to generate functional remote references, RMI servers must be able 
to ssupply a fully-qualified hostname or IP address that is resolvable from 
all RMI clients (an example of a fully-qualified hostname is foo.bar.
a remote callback operation then that program serves an RMI object and conse
quenntly, must be able to determine a resolvable hostname to use as its serv
er hostname in the remote references it passes to RMI clients. JVM's
serve remote objects may throw UnknownHostExceptions because the applet has 
failled to provide a useable server hostname.
If your RMI application throws an UnknownHostException, you can look at the 
resuulting stack trace to see if the hostname that the client is using to co
ntact its remote server is incorrect or not fully-qualified. If neces
java.rmi.server.hostname property on the server to the correct IP address or
 hosstname of the server machine and RMI will use this property's value to g
enerate remote references to the server.
C.3 My server is using a fully-qualified domain name or IP address, so why d
o I still get an UnknownHostException?
Depending upon the configuration of your network's name service, a fully-qua
lifiied hostname that is recognized on one RMI host may not be resolvable fr
om another RMI host. Some examples of where this situation may arise
Misconfigured DHCP servers may set the fully-qualified domain name of RMI se
rverr machines to be the domain name of the resolver domain instead of the d
omain in which the RMI server actually resides. In this case, RMI cli
domain will be unable to contact the server, because of the its incorrect do
mainn name.
The server machine is on a network that is configured to use Windows Interne
t Naaming Service (WINS). Hosts that are only registered under WINS may not 
be reachable by hosts that rely solely upon DNS.
The RMI client and server reside on opposite sides of a firewall. If your RM
I cllient lies outside a firewall and the server resides inside of it, the c
lient will not be able to make any remote calls to the server. If the
firewall, you will need to configure the RMI client to contact the server us
ing HTTP.
C.4 I am using the latest release of the JDK and I have a host that has mult
iplee IP addresses. RMI is choosing the wrong IP address for its server host
name, how do I work around this problem?
Set the java.rmi.server.hostname property to the correct IP address of the R
MI sserver machine. You can also specify that your server use a fully-qualif
ied hostname obtained from a name service by setting the property:
    java.rmi.server.useLocalHostname=true
C.5 How does RMI obtain a server hostname in each of the versions of the JDK
?
Methods RMI uses to obtain a server hostname in each of the versions of the 
JDK:
JDK1.1
RMI relied upon java.net.InetAddress.getLocalHost() to return a fully-qualif
ied domain name. InetAddress objects initialized local hostnames in a static
 block of code, performing a reverse lookup on the local IP address
However, on machines that were not connected to the network, this behavior c
auseed the program to hang while InetAddress looked for a hostname that coul
d not be found.
JDK1.1.1-1.1.6 & JDK1.2beta2-3
To work around the JDK1.1 problem on stand-alone systems, InetAddress was mo
difiied in JDK1.1.1 to only retrieve the [potentially unqualified] hostname 
returned from a native system call, which did not attempt to consult
modified to compensate for this change since the property java.rmi.server.ho
stnaame allowed users to override incorrect hostnames provided by InetAddres
s. RMI made no attempt to consult a name service and could default to
Later versions
To compensate for the many problems that were generated by the 1.1.1 change 
in ffunctionality of InetAddress, the following behavior has been integrated
 into the most recent versions of the JDK:
RMI will use an IP address or a fully-qualified domain name to identify a ma
chinne that serves a remote object. Server hostnames are initialized to the 
value obtained by performing the following actions:
By default, RMI uses the IP address of the server host as the server name fo
r reemote references.
If the property, java.rmi.server.hostname is set, RMI will use its value as 
the server hostname, and will not attempt to find a fully-qualified domain n
ame through any other method. This property takes precedence over al
server name.
If the property, java.rmi.server.useLocalHostname is set to true (by default
, thhe value of this property is false), RMI applies the following routine t
o obtain a hostname for the RMI server:
If the value returned by the InetAddress.getLocalHost().getHostName() method
 conntains a "." character, then RMI will assume that this value is the serv
er's fully-qualified domain name and will use it as the server hostna
Otherwise, RMI will spawn a thread to query the local name service for the f
ullyy-qualified domain name of the RMI server. If the name service takes too
 long to return, or the name service returns but its response does no
use the server's IP address obtained from InetAddress.getLocalHost().getHost
Addrress().
Users can override the default time (10 seconds or 10000 milliseconds) that 
RMI will look for a fully-qualified domain name by setting the following pro
perty:
sun.rmi.transport.tcp.localHostnameTimeOut=timeOutMillis
where timeOutMillis is the time that RMI will wait in milliseconds. For exam
ple:
            java -Dsun.rmi.transport.tcp.localHostnameTimeOut=2000 MyServerA
pp
When using activatable remote objects, it is recommended that RMI servers se
t thhe value of the java.rmi.server.useLocalHostname property to true. In ge
neral, hostnames are more stable than IP addresses. Activatable remot
than transient remote objects (for example,  survive a reboot). An RMI clien
t wiill be more likely to locate a remote object over a long period of time 
if it uses a qualified hostname rather than an explicit IP address.
C.6 Why do Naming.bind and Naming.lookup take an extraordinarily long time o
n Wiindows?
Most likely, your host's networking setup is incorrect. RMI uses the Java AP
I neetworking classes, in particular java.net.InetAddress, which will cause 
TCP/IP host name lookups - both host to address mapping and address t
InetAddress class does this for security reasons). On Windows, the lookup fu
nctiions are performed by the native Windows socket libraray, so the delays 
are happening not in RMI, but in the Windows libraries. If your host
usually a problem with the DNS server not knowing about the hosts involved i
n coommunication, and what you are experiencing are DNS lookup timeouts. Try
 specifying all the involved hostnames/addresses in the local file \w
or \windows\hosts. The format of a typical host file is:
    IPAddress     Machine Name
e.g.:
    208.2.84.61   homer
This should dramatically cut down the time it takes to make the first lookup
.
C.7 How do I use RMI on a Windows95 standalone machine, not connected to the
 nettwork?
To get RMI working on a Win95 machine that is not on a network, TCP/IP must 
be cconfigured. One way to accomplish this, is to configure an unused COM po
rt as a dedicated PPP or SLIP connection. Then disable DHCP and manua
(e.g. 192.168.1.1). You should then find that from a DOS Shell, you can ping
 youurself (for example, ping mymachine). You should now be able to run the 
stock RMI example.
C.8 Why do I get the exception "java.net.SocketException: Address already in
 usee" when I try to run the registry?
This exception means that the port that the RegistryImpl uses (by default 10
99) is already in use. You may have another registry already running on your
 machine and will need to stop it.
C.9 How can I use RMI through a firewall?
It depends on whether you need to traverse a firewall for outgoing calls or 
for incoming calls.
C.10 How can I make outgoing RMI calls through a local firewall?
There are three main methods: HTTP-tunneling, SOCKS, and downloaded socket f
actoories.
HTTP-tunneling
This well-worn method is popular since it requires almost no setup, and work
s quuite well in firewalled environments which permit handle HTTP through a 
proxy, but disallow regular outbound TCP connections.
If RMI fails to make a normal (or SOCKS) connection to the intended server, 
and it notices that a HTTP proxy server is configured, it will attempt to tu
nnel RMI requests through that proxy server, one at a time.
There are two forms of HTTP-tunneling, tried in order. The first is http-to-
portt; the second is http-to-cgi.
In http-to-port tunneling, RMI attempts a HTTP POST request to a http: URL d
ireccted at the exact hostname and port number of the target server. The HTT
P request contains a single RMI request. If the HTTP proxy accepts th
request to the listening RMI server, which will recognise the request and un
wrapp it. The result of the call is wrapped in a HTTP reply, which is return
ed through the same proxy.
Often, HTTP proxies will refuse to proxy requests to unusual port numbers. I
n thhis case, RMI will fall back to http-to-cgi tunneling. The RMI request i
s encapsulated in a HTTP POST request as before, but the request URL
http://hostname:80/cgi-bin/java-rmi.cgi?port=n (where hostname and n are the
 hosstname and port number of the intended server). There must be a HTTP ser
ver listening on port 80 on the server host, which will run the java-
the JDK), which will in turn forward the request to an RMI server listening 
on pport n. RMI can unwrap a HTTP-tunneled request without help from a http 
server, CGI script, or any other external entity. So, if the client's
to the server's port, then you don't need a java-rmi.cgi script at all.
To trigger the use of HTTP tunneling, the standard system property http.prox
yHosst must be set to the hostname of the local HTTP proxy. (There are repor
ts that some Navigator versions do not set this property.)
The major disadvantage of HTTP tunneling is that it does not permit inward c
allss or multiplexed connections. A secondary disadvantage is that the http-
to-cgi method opens a dramatic security hole on the server side, sinc
redirect any incoming request to any port.
SOCKS
The default implementation of sockets in the JDK will use a SOCKS server if 
avaiilable and configured. The system property socksProxyHost must have been
 set to the hostname of the SOCKS server; if the port number of the S
be specified in the socksProxyPort property.
This approach would appear to be the most generally-useful solution. As yet,
 SerrverSockets do not use SOCKS, so incoming calls must use another mechani
sm.
Downloaded socket factories
This is an innovation in JDK1.2beta4, allowing the server to specify the soc
ket factory that the clients must use. The clients must be running JDK1.2bet
a4 or later. Detailed instructions on creating custom RMI socket fac
The disadvantage of this approach is that the traversal of the firewall must
 be done by code provided by the RMI server side, which does not necessarily
 know how that traversal must be done, nor does it automatically hav
traverse the firewall.
C.11 How can I receive incoming RMI calls through a local firewall?
There are four main methods: known ports, transport-level bridge, applicatio
n-leevel proxy, and connection multiplexing.
Known Ports
If the exported objects are all exported on a known port on a known host, th
en tthat host and port can be explicitly permitted at the firewall. Normally
, RMI asks for port 0 (which is code for "any port"). In JDK1.2, ther
exportObject method to specify the exact port number. In JDK1.1, the server 
mustt subclass the RMISocketFactory and intercept requests to createServerSo
cket(0), replacing it with a request to bind to a specific port numbe
This approach has the disadvantage that it requires the assistance of the ne
tworrk administrator responsible for the local firewall. If the exported obj
ect is being run in a different location (because code was downloaded
firewall may be run by network administrators who don't know who you are.
Transport-level bridge
A transport-level bridge is a program that reads bytes from one TCP connecti
on aand writes them to another (and vice versa) without kno
--
※ 修改:·arbo 於 09月17日10:58:39 修改本文·[FROM: 匿名天使的家]
※ 来源:·听涛站 tingtao.dhs.org·[FROM: 匿名天使的家] 
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.214毫秒