//TCPTransport#exportObject publicvoidexportObject(Target target)throws RemoteException { /* * Ensure that a server socket is listening, and count this * export while synchronized to prevent the server socket from * being closed due to concurrent unexports. */ synchronized (this) { listen(); exportCount++; }
/* * Try to add the Target to the exported object table; keep * counting this export (to keep server socket open) only if * that succeeds. */ booleanok=false; try { super.exportObject(target); ok = true; } finally { if (!ok) { synchronized (this) { decrementExportCount(); } } } }
if (server == null) { if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + port + ") create server socket"); }
try { server = ep.newServerSocket(); /* * Don't retry ServerSocket if creation fails since * "port in use" will cause export to hang if an * RMIFailureHandler is not installed. */ Threadt= AccessController.doPrivileged( newNewThreadAction(newAcceptLoop(server), "TCP Accept-" + port, true)); t.start(); } catch (java.net.BindException e) { thrownewExportException("Port already in use: " + port, e); } catch (IOException e) { thrownewExportException("Listen failed on port: " + port, e); }
} else { // otherwise verify security access to existing server socket SecurityManagersm= System.getSecurityManager(); if (sm != null) { sm.checkListen(port); } } }
在构造socket的过程中,如果说端口是0的话,就会随机设置一个端口
1 2
if (listenPort == 0) setDefaultPort(server.getLocalPort(), csf, ssf);
privatevoidsetup(UnicastServerRef uref) throws RemoteException { /* Server ref must be created and assigned before remote * object 'this' can be exported. */ ref = uref; uref.exportObject(this, null, true); }
// UnicastRemoteObject#exportObject privatestatic Remote exportObject(Remote obj, UnicastServerRef sref) throws RemoteException { // if obj extends UnicastRemoteObject, set its ref. if (obj instanceof UnicastRemoteObject) { ((UnicastRemoteObject) obj).ref = sref; } return sref.exportObject(obj, null, false); }
/* Make sure to use the local stub loader for the stub classes. * When loaded by the local loader the load path can be * propagated to remote clients, by the MarshalOutputStream/InStream * pickle methods */ try { Class<?> stubcl = Class.forName(stubname, false, remoteClass.getClassLoader()); Constructor<?> cons = stubcl.getConstructor(stubConsParamTypes); return (RemoteStub) cons.newInstance(newObject[] { ref });
} catch (ClassNotFoundException e) { thrownewStubNotFoundException( "Stub class not found: " + stubname, e); } catch (NoSuchMethodException e) { thrownewStubNotFoundException( "Stub class missing constructor: " + stubname, e); } catch (InstantiationException e) { thrownewStubNotFoundException( "Can't create instance of stub class: " + stubname, e); } catch (IllegalAccessException e) { thrownewStubNotFoundException( "Stub class constructor not public: " + stubname, e); } catch (InvocationTargetException e) { thrownewStubNotFoundException( "Exception creating instance of stub class: " + stubname, e); } catch (ClassCastException e) { thrownewStubNotFoundException( "Stub class not instance of RemoteStub: " + stubname, e); } }
publicvoidsetSkeleton(Remote impl)throws RemoteException { if (!withoutSkeletons.containsKey(impl.getClass())) { try { skel = Util.createSkeleton(impl); } catch (SkeletonNotFoundException e) { /* * Ignore exception for skeleton class not found, because a * skeleton class is not necessary with the 1.2 stub protocol. * Remember that this impl's class does not have a skeleton * class so we don't waste time searching for it again. */ withoutSkeletons.put(impl.getClass(), null); } } }
static Skeleton createSkeleton(Remote object) throws SkeletonNotFoundException { Class<?> cl; try { cl = getRemoteClass(object.getClass()); } catch (ClassNotFoundException ex ) { thrownewSkeletonNotFoundException( "object does not implement a remote interface: " + object.getClass().getName()); }
// now try to load the skeleton based ont he name of the class Stringskelname= cl.getName() + "_Skel"; try { Class<?> skelcl = Class.forName(skelname, false, cl.getClassLoader());
if (host == null || host.length() == 0) { // If host is blank (as returned by "file:" URL in 1.0.2 used in // java.rmi.Naming), try to convert to real local host name so // that the RegistryImpl's checkAccess will not fail. try { host = java.net.InetAddress.getLocalHost().getHostAddress(); } catch (Exception e) { // If that failed, at least try "" (localhost) anyway... host = ""; } } LiveRefliveRef= newLiveRef(newObjID(ObjID.REGISTRY_ID), newTCPEndpoint(host, port, csf, null), false); RemoteRefref= (csf == null) ? newUnicastRef(liveRef) : newUnicastRef2(liveRef);
// read return value switch (returnType) { case TransportConstants.NormalReturn: break;
case TransportConstants.ExceptionalReturn: Object ex; try { ex = in.readObject(); } catch (Exception e) { thrownewUnmarshalException("Error unmarshaling return", e); }
// An exception should have been received, // if so throw it, else flag error if (ex instanceof Exception) { exceptionReceivedFromServer((Exception) ex); } else { thrownewUnmarshalException("Return type not Exception"); } // Exception is thrown before fallthrough can occur default: if (Transport.transportLog.isLoggable(Log.BRIEF)) { Transport.transportLog.log(Log.BRIEF, "return code invalid: " + returnType); } thrownewUnmarshalException("Return code invalid"); } }
/* StreamRemoteCall.done() does not actually make use * of conn, therefore it is safe to reuse this * connection before the dirty call is sent for * registered refs. */ ObjectreturnValue= unmarshalValue(rtype, in);
/* we are freeing the connection now, do not free * again or reuse. */ alreadyFreed = true;
/* if we got to this point, reuse must have been true. */ clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
/* Free the call's connection early. */ ref.getChannel().free(conn, true);
thrownewUnmarshalException("error unmarshalling return", e); } finally { try { call.done(); } catch (IOException e) { /* WARNING: If the conn has been reused early, * then it is too late to recover from thrown * IOExceptions caught here. This code is relying * on StreamRemoteCall.done() not actually * throwing IOExceptions. */ reuse = false; } }
} catch (RuntimeException e) { /* * Need to distinguish between client (generated by the * invoke method itself) and server RuntimeExceptions. * Client side RuntimeExceptions are likely to have * corrupted the call connection and those from the server * are not likely to have done so. If the exception came * from the server the call connection should be reused. */ if ((call == null) || (((StreamRemoteCall) call).getServerException() != e)) { reuse = false; } throw e;
} catch (RemoteException e) { /* * Some failure during call; assume connection cannot * be reused. Must assume failure even if ServerException * or ServerError occurs since these failures can happen * during parameter deserialization which would leave * the connection in a corrupted state. */ reuse = false; throw e;
} catch (Error e) { /* If errors occurred, the connection is most likely not * reusable. */ reuse = false; throw e;
} finally {
/* alreadyFreed ensures that we do not log a reuse that * may have already happened. */ if (!alreadyFreed) { if (clientRefLog.isLoggable(Log.BRIEF)) { clientRefLog.log(Log.BRIEF, "free connection (reuse = " + reuse + ")"); } ref.getChannel().free(conn, reuse); } } }
if (server == null) { if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + port + ") create server socket"); }
try { server = ep.newServerSocket(); /* * Don't retry ServerSocket if creation fails since * "port in use" will cause export to hang if an * RMIFailureHandler is not installed. */ Threadt= AccessController.doPrivileged( newNewThreadAction(newAcceptLoop(server), "TCP Accept-" + port, true)); t.start(); } catch (java.net.BindException e) { thrownewExportException("Port already in use: " + port, e); } catch (IOException e) { thrownewExportException("Listen failed on port: " + port, e); } ...... }
publicvoidrun() { try { executeAcceptLoop(); } finally { try { /* * Only one accept loop is started per server * socket, so after no more connections will be * accepted, ensure that the server socket is no * longer listening. */ serverSocket.close(); } catch (IOException e) { } } }
try { DataInputStreamin=newDataInputStream(conn.getInputStream()); do { intop= in.read(); // transport op if (op == -1) { if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + port + ") connection closed"); } break; }
if (tcpLog.isLoggable(Log.BRIEF)) { tcpLog.log(Log.BRIEF, "(port " + port + ") op = " + op); }
switch (op) { case TransportConstants.Call: // service incoming RMI call RemoteCallcall=newStreamRemoteCall(conn); if (serviceCall(call) == false) return; break;
case TransportConstants.Ping: ...... } } while (persistent);
publicvoiddispatch(Remote obj, RemoteCall call)throws IOException { // positive operation number in 1.1 stubs; // negative version number in 1.2 stubs and beyond... int num; long op;
try { // read remote call header ObjectInput in; try { in = call.getInputStream(); num = in.readInt(); if (num >= 0) { if (skel != null) { oldDispatch(obj, call, num); return; } else { thrownewUnmarshalException( "skeleton class not found but required " + "for client version"); } } op = in.readLong(); } catch (Exception readEx) { thrownewUnmarshalException("error unmarshalling call header", readEx); }
// make upcall on remote object Object result; try { result = method.invoke(obj, params); } catch (InvocationTargetException e) { throw e.getTargetException(); }
// marshal return value try { ObjectOutputout= call.getResultStream(true); Class<?> rtype = method.getReturnType(); if (rtype != void.class) { marshalValue(rtype, result, out); } } catch (IOException ex) { thrownewMarshalException("error marshalling return", ex); /* * This throw is problematic because when it is caught below, * we attempt to marshal it back to the client, but at this * point, a "normal return" has already been indicated, * so marshalling an exception will corrupt the stream. * This was the case with skeletons as well; there is no * immediately obvious solution without a protocol change. */ } } catch (Throwable e) { logCallException(e);
ObjectOutputout= call.getResultStream(false); if (e instanceof Error) { e = newServerError( "Error occurred in server thread", (Error) e); } elseif (e instanceof RemoteException) { e = newServerException( "RemoteException occurred in server thread", (Exception) e); } if (suppressStackTraces) { clearStackTraces(e); } out.writeObject(e); } finally { call.releaseInputStream(); // in case skeleton doesn't call.releaseOutputStream(); } }
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) { DGCImpl.dgcLog.log(Log.VERBOSE, "add object " + oe); }
synchronized (tableLock) { /** * Do nothing if impl has already been collected (see 6597112). Check while * holding tableLock to ensure that Reaper cannot process weakImpl in between * null check and put/increment effects. */ if (target.getImpl() != null) { if (objTable.containsKey(oe)) { thrownewExportException( "internal error: ObjID already in use"); } elseif (implTable.containsKey(weakImpl)) { thrownewExportException("object already exported"); }
static { /* * "Export" the singleton DGCImpl in a context isolated from * the arbitrary current thread context. */ AccessController.doPrivileged(newPrivilegedAction<Void>() { public Void run() { ClassLoadersavedCcl= Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( ClassLoader.getSystemClassLoader());
/* * Put remote collector object in table by hand to prevent * listen on port. (UnicastServerRef.exportObject would * cause transport to listen.) */ try { dgc = newDGCImpl(); ObjIDdgcID=newObjID(ObjID.DGC_ID); LiveRefref=newLiveRef(dgcID, 0); UnicastServerRefdisp=newUnicastServerRef(ref); Remotestub= Util.createProxy(DGCImpl.class, newUnicastRef(ref), true); disp.setSkeleton(dgc);
staticvoidregisterRefs(Endpoint ep, List<LiveRef> refs) { /* * Look up the given endpoint and register the refs with it. * The retrieved entry may get removed from the global endpoint * table before EndpointEntry.registerRefs() is able to acquire * its lock; in this event, it returns false, and we loop and * try again. */ EndpointEntry epEntry; do { epEntry = EndpointEntry.lookup(ep); } while (!epEntry.registerRefs(refs)); }
if (in instanceof ConnectionInputStream) { ConnectionInputStreamstream= (ConnectionInputStream)in; // save ref to send "dirty" call after all args/returns // have been unmarshaled. stream.saveRef(ref); if (isResultStream) { // set flag in stream indicating that remote objects were // unmarshaled. A DGC ack should be sent by the transport. stream.setAckNeeded(); } } else { DGCClient.registerRefs(ep, Arrays.asList(newLiveRef[] { ref })); }
if (in instanceof ConnectionInputStream) { ConnectionInputStreamstream= (ConnectionInputStream)in; // save ref to send "dirty" call after all args/returns // have been unmarshaled. stream.saveRef(ref); if (isResultStream) { // set flag in stream indicating that remote objects were // unmarshaled. A DGC ack should be sent by the transport. stream.setAckNeeded(); } } else { DGCClient.registerRefs(ep, Arrays.asList(newLiveRef[] { ref })); }