Имя узла и номер порта, который Вы видите в трассировке исключения, представляют адрес, на котором смотревший сервер полагает, что это слушает. В то время как Java Удаленный Вызов метода (Java RMI) сервер может теоретически быть на любом узле, это обычно - тот же самый узел как это, на котором реестр работает, и на различном порту.
Даже если сервер будет ошибочен о своем имени узла или IP-адресе (или имеет имя узла, которое просто не разрешимо клиентами), то это все еще экспортирует все свои объекты, используя, что ошибочное имя узла, но Вы будете видеть исключение каждый раз, когда Вы пытаетесь получить один из тех объектов.
Имя узла, в котором Вы определили Naming.lookup определять местоположение реестра не имеет никакого эффекта на имя узла, которое уже встраивается в удаленную ссылку на сервер.
Обычно, таинственное имя узла является неполным именем узла сервера, или частным именем, неизвестным nameservice клиента, или (в случае платформ Windows) Сеть сервера-> Идентификация-> Машинное Имя.
Соответствующее обходное решение должно установить системное свойство java.rmi.server.hostname запуская сервер. Значение свойства должно быть внешне достижимым именем узла (или IP-адрес) сервера - безотносительно работ когда определено как часть узла в Naming.lookup достаточно хорошо.
Тупиковый class может быть загружен, если сервер, который экспортирует удаленный объект, аннотирует упорядоченный тупиковый экземпляр java.rmi.server.codebase свойство, которое указывает на расположение от того, где тупиковый class может быть загружен. Следует установить java.rmi.server.codebase свойство на сервере, экспортирующем удаленный объект. В то время как удаленные клиенты могли установить это свойство, они будут тогда ограничены только получением удаленных объектов от указанной кодовой базы. Недопустимо предположить, что любой клиент, VM определит кодовую базу, которая решает к расположению Вашего объекта.
Когда удаленный объект упорядочивается по Java RMI (ли как параметр удаленному вызову или как возвращаемое значение), кодовая база для тупикового class получается Java RMI и используется, чтобы аннотировать сериализированный тупик. Когда тупик неупорядочивается, кодовая база используется, чтобы загрузить тупик classfile использование RMIClassLoader, если class не может уже быть найден в CLASSPATH или контекстом classloader для объекта получения, такого как кодовая база апплета.
Если _Stub class был загружен RMIClassLoader, тогда Java RMI уже знает который кодовая база использовать для ее аннотации. Если _Stub class был загружен из CLASSPATH, тогда нет никакой очевидной кодовой базы, и Java, с которым RMI консультируется java.rmi.server.codebase системное свойство, чтобы найти кодовую базу. Если системное свойство не устанавливается, то тупик упорядочивается с нулевой кодовой базой, что означает, что это не может использоваться, если у клиента нет соответствующей копии _Stub classfile в клиенте CLASSPATH.
Легко забыть определять свойство кодовой базы. Один способ обнаружить эту ошибку состоит в том, чтобы запуститься rmiregistry отдельно и без доступа к классам приложений. Это вызовет Naming.rebind перестать работать, если кодовая база опускается.
Нет. Можно установить Ваш java.rmi.server.codebase свойство, чтобы использовать любой допустимый протокол URL, такой как file или ftp. Используя сервер HTTP только делает Вашу жизнь более простой, обеспечивая автоматизированный механизм для загрузки файла class. Если у Вас нет доступа к серверу HTTP, ни наклону установить один, можно использовать наш маленький файловый сервер class, найденный в http://java.sun.com/javase/technologies/core/basic/rmi/class-server.zip.
Java реализация RMI пытается снова использовать открытые сокеты где только возможно для удаленных вызовов. Когда удаленный метод вызывается на тупик, который использует пользовательскую фабрику сокета, Java, реализация RMI снова использует открытое соединение (если кто-либо), пока тот сокет создавался эквивалентной фабрикой сокета. Так как клиентские фабрики сокета сериализируются клиентам, у единственного клиента может быть несколько отличных копий той же самой логической фабрики сокета. Чтобы гарантировать, что Java реализация RMI снова использует сокеты, создаваемые пользовательскими фабриками сокета, удостоверьтесь, что Ваши пользовательские клиентские классы фабрики сокета реализуют hashCode и equals методы соответственно. Если клиентская фабрика сокета не реализует эти методы правильно, другое разветвление - то, что тупики (использующий клиент снабжают фабрику сокетом), которые обращаются к тому же самому удаленному объекту, не будут равны.
Java реализация RMI пытается снова использовать серверные порты также. Это только сделает так, если будет существующий сокет сервера для порта, создаваемого эквивалентной фабрикой сокета. Удостоверьтесь фабрика сокета сервера, которую class реализует hashCode и equals методы также.
Если у Вашей фабрики сокета нет никакого состояния экземпляра, тривиальной реализации hashCode и equals методы являются следующим:
public int hashCode() { return 57; }
public boolean equals(Object o) { return this.getClass() == o.getClass() }
Java RMI поддерживает простое средство записи разговора клиента с оператором для того, чтобы отладить. Но нет никаких текущих планов поддерживать полнофункциональный, интерактивный, удаленный отладчик.
javaw команда выбрасывает вывод к stdout и stderr, так для того, чтобы отладить цели лучше работать java команда в отдельном окне так, чтобы можно было видеть, сообщила об ошибках. Чтобы сделать это, выполните команду как следующее:
start java EchoImpl
Советуют не использовать javaw команда во время разработки. Чтобы наблюдать действие сервера, запустите сервер с -Djava.rmi.server.logCalls=true.
Вы, вероятно, изменили один или более классов, которые использовались Java программы RMI, в то время как Ваша программа работала. Попытайтесь перезапустить весь Java приложения RMI (включая java.rmi.registry.RegistryImpl). Это должно разрешить вещи.
То, с чем Вы встретились, было распределенной мертвой блокировкой. В локальном случае VM VM может сказать, что вызов возражает, что "A" имеет блокировку и позволит вызову назад "A" продолжаться. В распределенном случае не может быть сделано никакое такое определение, таким образом, результатом является мертвая блокировка.
Распределенные объекты ведут себя по-другому чем локальные объекты. Если Вы просто снова используете локальную реализацию, не обрабатывая блокировку и отказ, то Вы, вероятно, получите непредсказуемые результаты.
Когда Вы делаете звонок в реестр, чтобы связать объект, реестр фактически связывает ссылку на тупик для удаленного объекта. Чтобы инстанцировать тупикового объекта, реестр, VM должен быть в состоянии загрузить свое определение class. VM (в этом случае сервер VM), который отправляет сериализированные формы тупика в удаленном вызове метода реестра, ответственен за аннотирование тупика расположением, с которого могут быть загружены его классы. Если тупики не будут аннотироваться должным образом, Java, то RMI бросит a ClassNotFoundException когда это пытается инстанцировать тупика.
Чтобы аннотировать классы должным образом, сервер должен установить значение java.rmi.server.codebase значение свойства к расположению (ям) тупиковых классов. Java RMI автоматически аннотирует сериализированную форму исходящих объектных экземпляров со значением java.rmi.server.codebase свойство.
ОТМЕТЬТЕ: возможно (и в небольшом количестве соответствующих сред) позволить rmiregistry неупорядочить тупиковые объекты, помещая все соответствующие тупиковые файлы class в ПУТЬ К КЛАССУ rmiregistry. Однако, rmiregistry не должен загрузить тупиковые классы. Если тупиковые классы будут доступны локально, то это будет использовать те классы. Используя ПУТЬ К КЛАССУ rmiregistry для тупикового развертывания требует, чтобы у всех VMs, которые ссылаются на тупиковый экземпляр, полученный из того реестра, был файл class тупика, установленный локально (в ПУТИ К КЛАССУ VM).
Например, если реестр загрузит тупиковые классы из своего ПУТИ К КЛАССУ, когда реестр отправит сериализированные тупиковые объекты другому VMs, то те сериализированные объекты будут аннотироваться значением реестра java.rmi.server.codebase свойство (который почти всегда будет нулем). Если VMs, у получения сериализированных тупиковых объектов от реестра нет файлов class для тех тупиков установленными локально тогда те VMs, вероятно, бросят a ClassNotFoundException.
Вместо этого если классы загружаются динамически с VM's сервера java.rmi.server.codebase аннотация, только сервер у VM должны быть тупиковые классы в его ПУТИ К КЛАССУ. С этим подходом развертывание приложения более просто, и возможно ввести новые тупиковые версии в рабочую распределенную систему.
где YourServerImpl имя Вашего сервера. Если Ваш сервер завис, можно получить дамп монитора и распараллелить дамп, делая ctrl-\ на Операционной системе Solaris™ (Солярис ОС) и ctrl-break на платформах Windows.
Свойства, которые начинаются"sun.rmi."только поддерживаются определенными версиями Java Комплект разработчика SE (JDK) программное обеспечение от Sun Microsystems. В то время как они"sun.rmi.*"свойства могут быть довольно полезными для отладки и настройки во времени выполнения, пожалуйста, отметьте, что их не считают частью общедоступного API, и их использование подвержено изменениям (или может быть удален полностью) в будущих версиях реализации.
Для Java клиент RMI, чтобы связаться с удаленным Java сервер RMI, клиент должен сначала содержать ссылку на сервер. Naming.lookup вызов метода является наиболее распространенным механизмом, которым клиенты первоначально получают ссылки на удаленные серверы. Удаленные ссылки могут быть получены другими средствами, например: все удаленные вызовы метода могут возвратить удаленные ссылки. Это что Naming.lookup делает; это использует известный тупик, чтобы сделать удаленный вызов метода rmiregistry, который отсылает удаленную ссылку назад на объект, который требуют lookup метод.
Каждая удаленная ссылка содержит имя узла сервера и номер порта, которые позволяют клиентам определять местоположение VM, который служит определенному удаленному объекту. Однажды Java у клиента RMI есть удаленная ссылка, клиент будет использовать имя узла и порт, обеспеченный в ссылке, чтобы открыть сокетное соединение с удаленным сервером.
Пожалуйста, отметьте, что с Java RMI клиент и сервер сроков может сослаться на ту же самую программу. Программа Java, которая действует как Java сервер RMI, содержит экспортируемый удаленный объект. Клиент RMI Java является программой, которая вызывает один или более методов на удаленный объект в другой виртуальной машине. Если VM выполняет обе из этих функций, он может упоминаться как клиент RMI и Java сервер RMI.
Во многих версиях JDK (все версии JDK кроме в v1.1 и последних выпусках), Java RMI может принять значение по умолчанию к использованию неразрешимого имени узла сервера (например: неполные имена, Windows Internet Naming Service (WINS) имена, или неполные имена DHCP). Когда Java, клиент RMI вызывает удаленный метод, используя ссылку, которая содержит неразрешимое имя узла сервера, клиент, бросит UnknownHostException.
Чтобы генерировать функциональные удаленные ссылки, Java, серверы RMI должны быть в состоянии предоставить полностью определенное имя узла или IP-адрес, который разрешим от всего Java клиенты RMI (пример полностью определенного имени узла foo.bar.com). Если Java, программа RMI обеспечивает удаленную работу обратного вызова, то та программа служит Java объект RMI и следовательно, должен быть в состоянии определить разрешимое имя узла, чтобы использовать в качестве его имени узла сервера в удаленных ссылках, это передает к Java клиенты RMI. VMs, которые делают звонки в апплеты, которые служат удаленным объектам, могут бросить UnknownHostExceptions, потому что апплет был не в состоянии обеспечить применимое имя узла сервера.
Если Ваш Java приложение RMI бросает UnknownHostException, можно смотреть на получающуюся трассировку стека, чтобы видеть, является ли имя узла, которое клиент использует, чтобы связаться с его удаленным сервером, неправильным или не полностью определенное. В случае необходимости можно установить java.rmi.server.hostname свойство на сервере к корректному IP-адресу или имени узла машины сервера и Java RMI будет использовать значение этого свойства, чтобы генерировать удаленные ссылки на сервер.
В зависимости от конфигурации службы имен Вашей сети полностью определенное имя узла, которое распознается на одном Java узел RMI, возможно, не разрешимо от другого Java узел RMI. Некоторые примеры, где эта ситуация может возникнуть:
Неправильно сконфигурированные серверы DHCP могут установить полностью определенное доменное имя Java машины сервера RMI, чтобы быть доменным именем домена преобразователя вместо домена, в котором Java фактически находится сервер RMI. В этом случае Java клиенты RMI вне домена DHCP сервера будет неспособен связаться с сервером из-за его неправильного доменного имени.
Машина сервера находится на сети, которая конфигурируется, чтобы использовать WINS. Узлы, которые только регистрируются под WINS, возможно, не достижимы узлами, которые полагаются исключительно на DNS.
Java клиент и сервер RMI находится на противоположных сторонах брандмауэра. Если Ваш Java, клиент RMI лежит вне брандмауэра и сервера, будет находиться в нем, то клиент не будет в состоянии сделать любые удаленные звонки в сервер. Если Java, клиент RMI лежит в брандмауэре, Вы должны будете сконфигурировать Java клиент RMI, чтобы связаться с сервером, используя HTTP.
Установите java.rmi.server.hostname свойство к корректному IP-адресу Java машина сервера RMI. Можно также определить, что Ваш сервер использует полностью определенное имя узла, полученное из службы имен, устанавливая свойство:
На Java RMI полагаются java.net.InetAddress.getLocalHost() возвратить полностью определенное доменное имя. InetAddress объекты инициализированные локальные имена узлов в статическом блоке кода, выполняя обратный поиск на локальном IP-адресе, чтобы получить локальное имя узла. Однако, на машинах, которые не были соединены с сетью, это поведение, вызванное программа, чтобы зависнуть в то время как InetAddress разыскиваемый имя узла, которое не могло быть найдено.
Работать вокруг JDK v1.1 проблема на автономных системах, InetAddress был изменен в JDK v1.1.1, чтобы только получить [потенциально неполное] имя узла, возвращенное из собственного системного вызова, который не пытался консультироваться со службой имен. Java RMI не был изменен, чтобы компенсировать это изменение начиная со свойства java.rmi.server.hostname разрешенные пользователи, чтобы переопределить неправильные имена узлов, обеспеченные InetAddress. Java RMI, предпринятый никакая попытка консультироваться со службой имен и, мог принять значение по умолчанию к использованию неполных имен узлов.
Компенсировать много проблем, которые были сгенерированы изменением v1.1.1 в функциональности InetAddress, следующее поведение было интегрировано в новые версии JDK:
RMI Java будет использовать IP-адрес или полностью определенное доменное имя, чтобы идентифицировать машину, которая служит удаленному объекту. Имена узлов сервера инициализируются к значению, полученному, выполняя следующие действия:
По умолчанию Java RMI использует IP-адрес узла сервера как имя сервера для удаленных ссылок.
Если свойство java.rmi.server.hostname устанавливается, Java RMI будет использовать свое значение в качестве имени узла сервера, и не будет пытаться найти полностью определенное доменное имя через любой другой метод. Это свойство имеет приоритет по всем другим средствам по обнаружению Java имя сервера RMI.
Если свойство java.rmi.server.useLocalHostname устанавливается в true (по умолчанию значение этого свойства false), Java RMI применяет следующую подпрограмму, чтобы получить имя узла для Java сервер RMI:
Если значение, возвращенное InetAddress.getLocalHost().getHostName() метод содержит "." символ, тогда Java, RMI предположит, что это значение является полностью определенным доменным именем сервера и будет использовать его в качестве имени узла сервера.
Иначе, Java RMI породит поток, чтобы запросить локальную службу имен для полностью определенного доменного имени Java сервер RMI. Если служба имен берет слишком долго, чтобы возвратиться, или возвраты службы имен, но ее ответ не содержат "." тогда Java, из которого RMI будет использовать IP-адрес сервера, полученный InetAddress.getLocalHost().getHostAddress().
Пользователи могут переопределить время значения по умолчанию (10 секунд или 10000 миллисекунд), что Java RMI будет искать полностью определенное доменное имя, устанавливая следующее свойство: sun.rmi.transport.tcp.localHostnameTimeOut=timeOutMillis где timeOutMillis является временем, когда Java RMI будет ожидать в миллисекундах. Например:
При использовании activatable удаленных объектов рекомендуется что Java набор серверов RMI значение java.rmi.server.useLocalHostname свойство к true. Вообще, имена узлов более устойчивы чем IP-адреса. Удаленные объекты Activatable имеют тенденцию длиться дольше чем переходные удаленные объекты (например, переживая перезагрузку). Клиент RMI Java, более вероятно, определит местоположение удаленного объекта за длительный период времени, если это будет использовать квалифицированное имя узла, а не явный IP-адрес.
Наиболее вероятно сетевая установка Вашего узла является неправильной. Java RMI использует сетевые классы API Java в особенности java.net.InetAddress, который будет вызывать поиски имени хоста TCP/IP - и узел отображения адресов и адресоваться к отображению имени узла ( InetAddress class делает это для соображений безопасности). На платформах Windows функции поиска выполняются собственной библиотекой сокета, таким образом, задержки происходят не в Java RMI, а в библиотеках. Если Ваш узел устанавливается, чтобы использовать DNS, то это обычно - проблема с сервером DNS, не зная об узлах, включенных в передачу, и что Вы испытываете, тайм-ауты поиска DNS. Попытайтесь определить все включенные имена узлов/адреса в локальном файле \winnt\system32\drivers\etc\hosts или \windows\hosts. Формат типичного файла узла:
IPAddress Machine Name
например:
192.0.2.61 homer
Это должно существенно сократить время, которое требуется, чтобы сделать первый поиск.
Чтобы получить Java RMI, работающий над машиной Windows 95, которая не находится на сети, TCP/IP должен быть сконфигурирован. Один способ выполнить это состоит в том, чтобы сконфигурировать неиспользованный COM-порт как выделенный PPP или SLIP соединение. Затем отключите DHCP и вручную сконфигурируйте IP-адрес (например. 192.168.1.1). Следует тогда найти, что от DOS Shell, можно проверить с помощью ping-запросов себя (например, проверить с помощью ping-запросовmymachine). Следует теперь быть в состоянии использовать Java RMI на машине.
Это исключение означает что порт что RegistryImpl использование (по умолчанию 1099) уже находится в использовании. Вы можете иметь другой реестр, работающий на Вашей машине, и должны будете остановить это.
Есть три основных метода: туннелирование HTTP, SOCKS, и загруженные фабрики сокета.
Туннелирование HTTP
Этот затасканный метод популярен, так как он не требует почти никакой установки, и работает вполне хорошо в firewalled средах, которые разрешают Вам обрабатывать HTTP через прокси, но отвергают регулярные исходящие соединения TCP.
Если Java, RMI не в состоянии сделать нормальное (или SOCKS) соединением с намеченным сервером, и это заметит, что прокси-сервер HTTP конфигурируется, то это попытается туннелировать Java запросы RMI через тот прокси-сервер по одному.
Есть две формы туннелирования HTTP, которое попробовали в порядке. Первым является http к порту; вторым является http-to-cgi.
В туннелировании http к порту Java RMI делает попытку запроса POST HTTP к a http: URL, направленный на точное имя узла и номер порта целевого сервера. Запрос HTTP содержит единственный Java запрос RMI. Если прокси HTTP примет этот URL, то он передаст запрос POST к Java слушания сервер RMI, который распознает запрос и развернет его. Результат вызова обертывается в ответ HTTP, который возвращается через тот же самый прокси.
Часто, прокси HTTP откажутся проксировать запросы к необычным номерам портов. В этом случае Java RMI отступит к туннелированию http-to-cgi. Java запрос RMI инкапсулируется в запросе POST HTTP как прежде, но запросе URL, имеет форму http://hostname:80/cgi-bin/java-rmi.cgi?port=n (где имя узла и n являются именем узла и номером порта намеченного сервера). Должен быть сервер HTTP, слушающий на порту 80 на узле сервера, который будет работать java-rmi.cgi сценарий (предоставленный JDK), который поочередно передаст запрос к Java сервер RMI, слушающий на порту n. Java RMI может развернуть туннелированный HTTP запрос без справки от http сервера, сценария CGI, или любого другого внешнего объекта. Так, если прокси HTTP клиента может соединиться непосредственно с портом сервера, то Вы не нуждаетесь в a java-rmi.cgi сценарий вообще.
Инициировать использование туннелирования HTTP, стандартного системного свойства http.proxyHost должен быть установлен в имя узла локального прокси HTTP. (Есть отчеты, что некоторые версии Навигатора не устанавливают это свойство.)
Главный недостаток туннелирования HTTP - то, что оно не разрешает входящие вызовы или мультиплексированные соединения. Вторичный недостаток - то, что http-to-cgi метод открывает драматическую дыру в системе безопасности на стороне сервера, с тех пор без модификации это перенаправит любой входящий запрос к любому порту.
SOCKS
Реализация по умолчанию сокетов в JDK будет использовать сервер SOCKS при наличии и сконфигурированный. Системное свойство socksProxyHost должно быть, был установлен в имя узла сервера SOCKS; если номер порта сервера SOCKS не 1080, это должно быть определено в socksProxyPort свойство.
Этот подход, казалось бы, был бы самым обычно полезным решением. Пока еще, ServerSockets не используйте SOCKS, таким образом, входящие вызовы должны использовать другой механизм.
Загруженные фабрики сокета
Это - новшество в JDK, позволяя сервер определить фабрику сокета, которую должны использовать клиенты. Клиенты должны выполнять J2SE v1.2 или позже. См., что учебное руководство Использует Пользовательские Фабрики Сокета с Java RMI для деталей.
Недостаток этого подхода - то, что обход брандмауэра должен быть сделан кодом, обеспеченным Java сторона сервера RMI, которая не обязательно знает, как тот обход должен быть сделан, и при этом у этого автоматически нет достаточного полномочия пересечь брандмауэр.
Есть три основных метода: известные порты, мосты на транспортном уровне, и прокси уровня приложения.
Известные Порты
Если экспортируемые объекты все экспортируются на известном порту на известном узле, то тот узел и порт могут быть явно разрешены в брандмауэре. Обычно, Java, который RMI просит порт 0 (который является кодом для "любого порта"). В JDK есть дополнительный параметр exportObject метод, чтобы определить точный номер порта. В JDK v1.1, сервер должен разделить на подклассы RMISocketFactory и прерывание запрашивает к createServerSocket(0), замена этого с запросом, чтобы связать с определенным номером порта.
У этого подхода есть недостаток, что это требует помощи администратора сети, ответственного за локальный брандмауэр. Если экспортируемый объект выполняется в различном расположении (потому что код был загружен на тот сайт), то локальный брандмауэр может быть выполнен администраторами сети, которые не знают, кто Вы.
Мосты на транспортном уровне
Мост на транспортном уровне является программой, которая читает байты из одного соединения TCP и пишет их другому (и наоборот), не зная или заботясь, что представляют байты.
Идея здесь состоит в том, чтобы экспортировать объекты таким способом, которым любой вне брандмауэра, кто хочет вызвать удаленные методы на том объекте вместо этого, связывается с различным портом (возможно, на различной машине). У того различного порта есть рабочая программа, которая делает второе соединение с реальным сервером и затем качает байты каждый путь.
Хитрая часть убеждает клиент соединяться с мостом. Загружаемая фабрика сокета (JDK, v1.2 или позже) может сделать это эффективно; иначе, возможно установить java.rmi.server.hostname свойство, чтобы назвать узел моста и принять меры, чтобы номера портов были тем же самым.
Прокси уровня приложения
Этот подход является довольно мало работы, но приводит к очень безопасному расположению. Программа прокси работает на узле брандмауэра (тот, к которому можно получить доступ снаружи так же как внутри). Когда внутренний сервер намеревается сделать экспортируемый объект доступным для мира, он связывается с прокси-сервером и дает этому удаленную ссылку. Прокси-сервер создает объект прокси (новый удаленный объект, находящийся в прокси-сервере), который реализует те же самые удаленные интерфейсы как оригинал. Прокси-сервер возвращает удаленную ссылку для нового объекта прокси к внутреннему серверу, который передает это к внешнему миру (так или иначе).
Когда посторонний делает запрос к прокси, прокси сразу вперед звонок в его исходный объект на внутреннем сервере. Использование прокси прозрачно постороннему (но не к внутреннему серверу, кто должен решить, передать ли исходную ссылку или ссылку прокси когда говорящий с кем-либо).
Само собой разумеется это требует значительной установки и сотрудничества локальных администраторов сети.
Прежде всего, какое сотрудничество можно ожидать от клиентского брандмауэра?
В самом пессимистическом случае клиентский брандмауэр не позволяет прямых соединений TCP и имеет только прокси-сервер HTTP так, чтобы firewalled клиенты могли "бродить по сети". В этом случае Ваш узел сервера получит соединения в порту 80 содержащий Java запросы RMI, встроенные в запросы HTTP. Можно использовать сервер HTTP с java-rmi.cgi программа, или можно выполнить Java сервер RMI непосредственно на порту 80. Так или иначе сервер не может использовать объекты обратного вызова, экспортируемые клиентами..
Более оптимистический случай - то, что клиент может сделать прямые связи с сервером, но не может получить входящие соединения от сервера. В этом случае объекты обратного вызова не обычно возможны также.
Самый консервативный подход, не принимая справки от клиентских администраторов брандмауэра:
Избегайте использования объектов обратного вызова
Выполните свои серверы на `общедоступных' портах такой как 80, 81, 8001, или 443
Если серверы не работают на порту 80, также:
Поместите способный к CGI сервер HTTP в порт 80 использований java-rmi.cgi сценарий; или
Выполните редиректор порта (такой как DeleGate) на порту 80, который примет соединения и сразу соединится с реальным портом сервера, чтобы передать байты назад и вперед. Это вызовет getClientHost() чтобы возвратить вводящую в заблуждение информацию, так что не делайте Реестра доступным через этот метод, если это не находится на различном узле.
Мы обеспечили пример, который демонстрирует, как реализовать java-rmi.cgi сценарий используя сервлет. Пример также объясняет, как выполнить удаленный объект в сервлете VM.
Отметьте: Если Вы не понимаете роль это java-rmi.cgi игры в туннелирующих удаленных вызовах метода по HTTP, пожалуйста, см. вопрос о FAQ расценить HTTP, туннелирующий в Java RMI.
Да. Ваш удаленный объект должен будет реализовать java.rmi.server.Unreferenced интерфейс (в дополнение к любым другим необходимым интерфейсам). Java RMI обеспечит уведомление, вызывая unreferenced метод, когда все клиенты разъединяются. Ваша реализация unreferenced метод определит, какое действие Ваш удаленный объект должен брать получение такого уведомления. Однако, если есть ссылка в реестре, то Unreferenced.unreferenced метод никогда не будут вызывать.
Никакие выдающиеся сохраненные клиентом ссылки на удаленные объекты в VM, и
Никакие потоки недемона, выполняющиеся в VM.
Однако, только потому что нет никаких локальных или удаленных ссылок на удаленный объект, не означает, что объект будет собран "мусор" своевременно. Это действительно означает, что память удаленного объекта может быть собрана, чтобы удовлетворить выделение памяти, которое иначе перестало бы работать (с OutOfMemoryError).
Хотя API Java не определяет своевременность набора так или иначе, есть определенная причина, какой может походить на неопределенно задержанный набор удаленных объектов в JDK v1.1 реализация. Под покрытиями Java время выполнения RMI содержит слабую ссылку на экспортируемые удаленные объекты в таблице (чтобы отследить локальные так же как удаленные ссылки на объект). Единственный механизм слабой ссылки, доступный в JDK v1.1 VM, использует неагрессивную, кэширующуюся политику набора (подходящий для браузера), таким образом, объекты, которые только "слабо достижимы", не будут собраны, пока локальный GC не решает, что это действительно нуждается в той памяти, чтобы удовлетворить другое выделение. Для неактивного сервера это никогда не могло происходить. Но если память будет необходима, то серверный объект, на который нессылаются, будет собран.
Платформа SE Java включает новую инфраструктуру, что Java, который RMI будет использовать, чтобы сократить значительно количество условий, при которых происходит эта проблема.
Когда Java, время выполнения RMI в клиенте, VM обнаруживает, что на удаленный объект больше не ссылаются локально, это асинхронно, уведомляет сервер относительно быстро так, чтобы сервер мог обновить набор объекта, на который ссылаются, соответственно. Распределенный сборщик "мусора" использует арендный договор, связанный с каждой сохраненной клиентом ссылкой удаленного объекта, и возобновляет арендные договоры удаленным объектам, в то время как клиент все еще содержит такие ссылки. Цель механизма возобновления арендного договора состоит в том, чтобы позволить серверу обнаруживать аварийное завершение клиентов, так, чтобы сервер не держался за удаленный объект навсегда из-за клиента, который не смог отправить соответствующее сообщение, на которое "нессылаются" прежде, чем это прекратило работать. В этом контексте, клиент, вызывающий System.exit() считается аварийным завершением, потому что оно не позволяет времени выполнения RMI отправлять соответствующие сообщения, на которые "нессылаются", серверу. Выполнение System.runFinalizersOnExit в клиенте прежде, чем завершение не достаточно, потому что не вся необходимая обработка обрабатывается в финализаторе; то есть сообщение, на которое "нессылаются", не будет отправлено серверу. (Используя "runFinalizersOnExit" является обычно опрометчивым и склонным к мертвой блокировке так или иначе.)
Если Вы должны использовать System.exit() завершать клиент VM, гарантировать, что удаленные ссылки, сохраненные, в котором VM очищаются более своевременным способом, следует удостовериться, что нет никаких удаленных ссылок, все еще достижимых. Явно нулевой любые локальные ссылки, чтобы сделать их недостижимый из выполнения потоков. Это также может помочь выполнить полную сборку "мусора" и выполнить финализаторы перед выходом:
Если Вы ожидаете арендного договора клиента, чтобы закончиться, и unreferenced() метод тогда вызовет Java реализацией RMI (помните, что реестр является также клиентом с этой целью, так как это содержит ссылки для всей своей привязки).
Если клиент содержит удаленную ссылку, она также содержит арендный договор для той ссылки, которая должна быть возобновлена (связываясь с сервером и делая a dirty() вызовите). Когда заключительный арендный договор для экспортируемого объекта истек или закрылся, объект считают нессылаемым, и (если это реализует java.rmi.Unreferenced) unreferenced() метод будет вызван.
Если у двух или больше клиентов есть ссылки на тот же самый удаленный объект, unreferenced() метод не вызовут, пока все они не истекли их арендные договоры о нем. Следовательно, если Вы используете этот метод, чтобы отследить отдельные клиенты, у каждого клиента должна быть ссылка на его собственное Unreferenced объект.
Время истечения срока арендного договора определяется сервером, где это может быть установлено, используя системное свойство, java.rmi.dgc.leaseValue, чье значение находится в миллисекундах. Установить это в более короткое время (например: 30 секунд), запустите сервер как это:
java -Djava.rmi.dgc.leaseValue=30000 ServerMain
Значение по умолчанию является 600000 миллисекунд (или 10 минутами).
Клиент возобновит каждый арендный договор, когда он на полпути истечется. Если интервал арендного договора будет слишком короток, то клиент потратит впустую много сетевой пропускной способности, напрасно возобновляющей ее арендный договор. Если интервал арендного договора будет слишком короток, то клиент будет неспособен возобновить арендный договор вовремя, и экспортируемый объект может быть удален в результате.
Будущие выпуски Java, RMI может лишить законной силы удаленные ссылки, если они не в состоянии возобновить свои арендные договоры (чтобы сохранить ссылочную целостность); недопустимо положиться на возможность использовать устарелые ссылки на удаленные объекты.
Отметьте, что необходимо только ожидать тайм-аута, если клиентская машина отказывает. Если клиент имеет некоторый контроль, когда разъединение происходит, это может отослать DGC чистый вызов быстро, делая использование Unreferenced довольно своевременный. Можно способствовать этому процессу, обнуляя любые ссылки, которые клиент может иметь к удаленному объекту и затем вызову System.gc(). (В v1.1.x Вам, вероятно, придется выполнить финализаторы синхронно и затем выполнить GC снова.)
Поскольку ничто, что делает сервер, не может отличить разрушенный узел от сетевой задержки.
Если или когда разрушенный клиент более поздние перезапуски и контакты сервер, сервер может вывести, что клиент потерял его состояние. Если соединение TCP считается открытое между клиентом и сервером всюду по их взаимодействию, то сервер может обнаружить клиентскую перезагрузку когда более поздняя попытка записать в сбои соединения (включая почасовый TCP keepalive пакет, если включено). Однако, Java, RMI разрабатывается, чтобы не потребовать таких постоянных соединений, поскольку это повреждает масштабируемость и не помогает очень.
Учитывая, что абсолютно невозможно немедленно определить, когда сетевая коллега отказывает или становится иначе недоступной, следует решить, как Ваше приложение должно вести себя, когда коллега прекращает отвечать.
Главные инструменты, которые Вы имеете для этой задачи, являются тайм-аутами и сбросами. После тайм-аута можно прийти к заключению, что коллега недостижима, но коллега должна знать о тайм-ауте так, чтобы это бросило пытаться достигнуть Вас. Лизинговый механизм разрабатывается, чтобы сделать это полуавтоматически.
Сброс является чисткой существующего состояния, сохраненного для коллеги. Например, клиент может вызвать сброс, когда он сначала регистрируется в его сервере, заставляя сервер отбросить любое предыдущее состояние, сохраненное для того клиента (выводившего, что клиент перезапустил без памяти предыдущего, мертвого, сеанса).
Часто, цель состоит в том, чтобы иметь и поддержать категорический список клиентов в сервере, и сохранить это актуальным без ошибки или отказа. Так как отказ и задержка могут произойти в любое время в сетевой системе, определенная степень ошибки в списке должна ожидаться. Если арендный договор или другой механизм используются, чтобы осуществить тайм-аут, то проблема утечки ресурса решается. Если бы проблема устаревших данных более серьезна - то есть, если бы это вмешалось бы в корректную работу - тогда это должно быть явно очищено в случаях, где это иначе имело бы эффект.
Например, если бизнес-объект блокируется для того, чтобы отредактировать человеком, и сеанс умирает, то блокировка должна быть повреждена так или иначе. В этом случае блокировка нуждалась бы в тайм-ауте, но если тот же самый человек сразу входит в систему и ожидает не должным быть ожидать тайм-аута, чтобы истечь, новый сеанс должен или принять блокировку или утверждать, что пользователь не содержит блокировок (позволяющий сервер безопасно уничтожить блокировку).
Java RMI не поддерживает или "inout" параметры, точно так же как остальная часть базового языка программирования Java. Все удаленные вызовы являются методами удаленного объекта. Локальные объекты передает копия, и удаленные объекты передают в отношении тупика. Для получения дополнительной информации см. Передачу параметров в Удаленном Вызове метода в Java Спецификация RMI.
В Java RMI клиент видит только тупик для исходного объекта. Тупик реализует только удаленные интерфейсы и их удаленные методы и не может быть брошен назад к исходной реализации class, потому что это - только тупик.
Так, невозможно передать ссылку удаленного объекта от сервера до клиента, и затем отослать это назад к серверу и быть в состоянии бросить это назад к исходной реализации class. Можно, тем не менее, использовать ссылку удаленного объекта на сервере, чтобы сделать удаленный звонок в объект.
Если Вы должны счесть реализацию class снова, Вы должны будете сохранить таблицу, которая отображает удаленную ссылку на реализацию class.
То, что можно сделать, "перенестись" java.util.Observable и java.util.Observer с новыми интерфейсами (Вы могли вызвать их RemoteObservable и RemoteObserver). В этих новых интерфейсах сделайте каждый бросок методов java.rmi.RemoteException. Затем, Ваши удаленные объекты могут реализовать эти интерфейсы.
Отметьте, что начиная с "обернутого" неудаленного объекта не расширяется java.rmi.server.UnicastRemoteObject, Вы должны будете явно экспортировать объект, используя exportObject метод UnicastRemoteObject. В выполнении этого, хотя, Вы проигрываете java.rmi.server.RemoteObject реализации equals, hashCode, и toString методы.
Когда клиент делает работу "поиска", соединение делается к rmiregistry на указанном узле. Вообще, новое соединение может или не может быть создано для удаленного вызова. Соединения кэшируются Java транспорт RMI для будущего использования, так, если соединение свободно правильному месту назначения для удаленного вызова, то это используется. Клиент не может явно закрыть соединение с сервером, так как соединениями управляют в Java транспортный уровень RMI. Соединения будут время, если они будут неиспользованы сроком на время.
JRMP и реализации IIOP RMI Java заменят каждый удаленный объект соответствующим тупиком (того же самого протокола), даже глубоко в графиках сериализуемых объектов.
Мы разработали транспортные интерфейсы так, чтобы различные реализации этих интерфейсов могли использоваться Java RMI. В более ранних выпусках эта абстракция использовалась в наших целях и не была представлена для общего использования. Теперь, в JDK, Java RMI поддерживает фабрики сокета клиента и сервера, которые могут использоваться, чтобы сделать Java перекличками RMI не TCP базируемые сокеты.
Java RMI не опрашивает на избранных вызовах. Есть поток, который просыпается каждый так часто и опрашивает таблицу экспортируемых удаленных объектов. Это "пожинает" поток, используется в целях распределенного сборщика "мусора".
Java RMI снова использует сокетные соединения между клиентом и сервером когда бы ни было возможно. Текущая реализация создает дополнительные сокеты по требованию, когда они необходимы. Например, если существующий сокет используется вызовом тогда, новый сокет создается для нового вызова. Как правило, есть по крайней мере два сокета, открытые, так как распределенный сборщик "мусора" должен выполнить удаленные вызовы, когда удаленные объекты возвращаются из сервера. Если кэшируемое соединение остается неиспользованным сроком на время, соединение закрывается.
Это - известная проблема, не с Java RMI, а с потоком, который читает стандартный ввод. Поток не уступает на чтении блокирования, но вместо этого остается рабочим, едва позволяя слушателю получить любые циклы. Мы попробовали два обходных решения, которые кажутся успешными: установите основной поток (один ввод стандарта чтения) к более низкому приоритету, или урожаю, в то время как байты не доступны в потоке прежде фактически считать это.
Неудаленные объекты передает копия, так, если Вы хотите иметь новые значения массива, отраженного в клиенте, необходимо отослать их назад как параметр возврата.
Да. Инициализатор выполняется в каждом VM, который загружает удаленный интерфейс, создавая новую статическую переменную с указанными значениями. Так, у Вас есть отдельная копия этой статической переменной в каждом VM, который загружает удаленный интерфейс.
Метод LocateRegistry.getRegistry(String host) не связывается с реестром на узле, а скорее только ищет узел, чтобы удостовериться, что это существует. Так, даже при том, что этот метод успешно выполнялся, это не обязательно означает, что реестр работает на указанном узле. Это только возвращает тупик, который может тогда получить доступ к реестру.
Объектная Сериализация
1. Почему должен реализация классов Serializable чтобы быть записанным ObjectOutputStream?
Решение потребовать, чтобы классы реализовали java.io.Serializable интерфейс не был сделан слегка. Проект, требовавшийся баланс между потребностями разработчиков и потребностями системы быть в состоянии обеспечить предсказуемый и безопасный механизм. Самое трудное конструктивное ограничение, чтобы удовлетворить было безопасностью классов для языка программирования Java.
Если классы должны были быть отмечены как являющийся сериализуемым команда разработчиков, взволнованная, что разработчик, или из забвения, лени, или из невежества не мог бы объявить class, как являющийся Serializable и затем сделайте тот class бесполезным для RMI или в целях персистентности. Мы волновались, что требование поместит в разработчика бремя знания, как class должен был использоваться другими в будущем, чрезвычайно непостижимом условии. Действительно, наш предварительный проект, как отражено в альфа-API, пришел к заключению, что случай значения по умолчанию для class должен быть то, что объекты в class сериализуемы. Мы изменили наш проект только после соображений безопасности и правильности, убежденной нас, что значение по умолчанию должно было быть то, что объект не был сериализирован.
Ограничения безопасности
Первое рассмотрение, которое заставило нас изменять поведение значения по умолчанию объектов, к которым имеют отношение безопасность, и в особенности в конфиденциальности полей, которые, как объявляют, были частными, пакет, защищенный, или защищенный. Платформа Java ограничивает доступ к таким полям или для чтения или для записи к подмножеству объектов в пределах времени выполнения.
Никакое такое ограничение не может быть сделано на объекте, как только он был сериализирован; поток байтов, который является результатом объектной сериализации, может быть считан и изменен любым объектом, у которого есть доступ к тому потоку. Это предоставляет любой объектный доступ к состоянию сериализированного объекта, который может нарушить пользователей гарантий конфиденциальности языка, ожидают. Далее, байты в потоке могут быть изменены произвольными способами, позволяя реконструкцию объекта, который никогда не создавался в пределах защит платформы Java. Есть случаи, в которых воссоздание такого объекта могло поставить под угрозу не только гарантии конфиденциальности, ожидаемые пользователями платформы Java, но целостность платформы непосредственно.
Эти нарушения не могут быть предотвращены, так как вся эта мысль о сериализации состоит в том, чтобы позволить объекту быть преобразованным в форму, которая может быть перемещена за пределами платформы Java (и поэтому за пределами гарантий конфиденциальности и целостности той среды) и затем возвращена в среду. Требование, чтобы объекты были объявлены сериализуемый, действительно означает, что разработчик class должен принять активное решение позволить возможность такого нарушения в конфиденциальности или целостности. Разработчик, который не знает о сериализации, не должен быть открытым, чтобы пойти на компромисс из-за этого отсутствия знаний. Кроме того, мы надеялись бы, что разработчик, который объявляет, что class сериализуем, делает так после некоторой мысли о возможных последствиях того объявления.
Отметьте, что этот вид проблемы безопасности не является тем, с которым может иметь дело механизм менеджера безопасности. Так как сериализация предназначается, чтобы позволить транспорт объекта от одной виртуальной машины до некоторого другого (или по пространству, поскольку это используется в RMI, или в течение долгого времени, как тогда, когда поток сохраняется к файлу), механизмы, используемые для безопасности, должны быть независимыми от среды выполнения любой определенной виртуальной машины. Мы хотели избежать в максимально возможной степени проблемы возможности сериализировать объект в одной виртуальной машине и не бывший способный десериализовывать тот объект в некоторой другой виртуальной машине. Так как менеджер безопасности является частью среды выполнения, используя менеджера безопасности для сериализации нарушил бы это требование.
Принуждение сознательного решения
В то время как проблемы безопасности были первой причиной рассмотрения изменения проекта, причина, что мы чувствуем, состоит, по крайней мере в том, как убеждение состоит в том, что сериализация должна только быть добавлена к class после некоторого рассмотрения проекта. Слишком легко разработать class, который разваливается при сериализации и реконструкции. Требуя, чтобы разработчик class объявил поддержку интерфейса сериализации, мы надеялись, что разработчик также уделит некоторое внимание процессу сериализации того class.
Примеры легко привести. Много классов имеют дело с информацией, которая только имеет смысл в контексте времени выполнения, в котором существует определенный объект; примеры такой информации включают дескрипторы файлов, открытые сокетные соединения, информацию о безопасности, и т.д. С такими данными можно иметь дело легко, просто объявляя поля как transient, но такое объявление только необходимо, если объект собирается быть сериализированным. Новичок (или забывчивый, или поспешил) программист мог бы забыть отмечать поля как transient почти таким же способом он или она мог бы забыть отмечать class как реализацию Serializable интерфейс. Такой случай не должен привести к неправильному поведению; способ избежать этого не состоит в том, чтобы сериализировать объекты, не отмеченные как реализация Serializable.
Другим примером этого вида является "простой" объект, который является корнем графика, который охватывает большое количество объектов. Сериализация такого объекта могла привести к сериализации большого количества других, начиная с работ сериализации по всему графику. Выполнение чего-то вроде этого должно быть сознательным решением, не тем, которое происходит по умолчанию.
Потребность в этом виде мысли была приведена домой нам в группе, когда мы проходили через основной API Java библиотеки class, отмечая системные классы как сериализуемый (где необходимо). Мы первоначально думали, что это будет довольно простым процессом, и что большинство системных классов могло только быть отмечено как реализация Serializable и затем используйте реализацию по умолчанию без других изменений. То, что мы нашли, было то, что это было намного менее часто случаем, чем мы подозревали. В большом количестве классов осторожная мысль должна была быть дана тому, должно ли поле быть отмечено как transient или ли имело смысл сериализировать class вообще.
Конечно, нет никакого способа гарантировать, что разработчик программиста или class фактически собирается думать об этих проблемах, отмечая class как сериализуемый. Однако, требуя, чтобы class объявил себя как реализация Serializable интерфейс мы действительно требуем, чтобы некоторая мысль была дана программистом. Наличие сериализации быть состоянием по умолчанию объекта означало бы, что нехватка мысли могла вызвать плохие эффекты в программе, что-то, чего общий замысел платформы Java попытался избежать.
2. Который JDK v1.1 системные классы отмечаются сериализуемые?
Удаленный. Эта информация легко доступна из документации API, сгенерированной javadoc инструмент.
3. У меня есть проблемы, десериализовывая JDK v1.0.2AWT компоненты. Как я могу сделать эту работу?
То, когда Вы сериализируете виджеты AWT, также сериализированный Коллега, возражает, что отображают функции AWT на локальную оконную систему. Когда Вы десериализовываете (воссоздают) виджеты AWT, старые Коллеги воссоздаются, но они являются устаревшими. Коллеги являются собственными к локальной оконной системе и содержат указатели на структуры данных в локальном адресном пространстве, и поэтому не могут быть перемещены.
Как работа вокруг, следует сначала удалить высокоуровневый виджет из его контейнера (таким образом, виджеты больше не "живы"). Коллеги отбрасываются в этой точке, и Вы сохраните только состояние виджета AWT. Когда Вы позже десериализовываете и читаете, виджеты въезжают задним ходом, добавляют высокоуровневый виджет к фрейму, чтобы заставить виджеты AWT появиться. Вы, возможно, должны добавить a show вызвать.
В JDK v1.1 и позже, виджеты AWT сериализуемы. java.awt.Component Реализации class Serializable.
4. Объектная сериализация поддерживает шифрование?
Объектная сериализация не содержит шифрования/дешифрования сам по себе. Это пишет в и читает из стандартных потоков в API Java, таким образом, это может быть вместе с любой доступной технологией шифрования. Объектная сериализация может использоваться многими различными способами. Кроме только записи и чтения в и от файлов, это может также использоваться для Java RMI, чтобы связаться между узлами.
Использование RMI листового шифрования сериализации и дешифрование к более низкому сетевому транспорту. Мы ожидаем, что, когда безопасный канал необходим, сетевые соединения будут сделаны, используя SSL и т.п. (см. Используя RMI с SSL).
5. Объектные классы сериализации являются потоковыми. Как я пишу объекты в файл произвольного доступа?
В настоящий момент нет никакого прямого способа записать объекты в файл произвольного доступа.
Можно использовать ByteArrayInputStream и ByteArrayOutputStream объекты как промежуточное звено помещают в запись, и считайте байты в и от файла произвольного доступа и создайте ObjectInputStreams и ObjectOutputStreams от потоков байтов, чтобы транспортировать объекты. Только необходимо удостовериться, что у Вас есть весь объект в потоке байтов, или чтение/запись объекта перестанет работать.
Например, java.io.ByteArrayOutputStream может использоваться, чтобы получить байты ObjectOutputStream. От этого можно получить результат в форме байтового массива. Это поочередно может использоваться с ByteArrayInputStream как входной к ObjectInput поток.
6. Когда локальный объект сериализируется и передается в качестве параметра в Java вызов RMI, байт-коды для методов локального объекта, которые также передают? Что относительно объектной последовательности, если удаленное приложение VM "сохраняет" объектный дескриптор?
Байт-коды для методов локального объекта не передают непосредственно в ObjectOutputStream, но class объекта, возможно, должен быть загружен получателем, если class не уже доступен локально. Файлы самого class не сериализируются, только имена классов. Все классы должны быть в состоянии быть загруженными во время десериализации, используя нормальные механизмы загрузки class. Для апплетов это означает, что они загружаются AppletClassLoader.
Нет никаких гарантий последовательности локальных объектов, которые передают к удаленному VM, так как такие объекты передают, копируя их содержание (истинная передача значением).
7. Как может я создавать ObjectInputStream от ObjectOutputStream без файла промежуточный?
ObjectOutputStream и ObjectInputStream работайте к/от любому потоковому объекту. Вы могли использовать a ByteArrayOutputStream и затем получите массив и вставьте его в a ByteArrayInputStream. Вы могли также использовать переданные по каналу потоковые классы также. Любой java.io class, который расширяется OutputStream и InputStream классы могут использоваться.
8. Я создаю объект и затем отправляю его через сеть, используя writeObject метод и получает это использующий readObject метод. Если я тогда изменяю значение поля в объекте и отправляю это как прежде, объект что readObject возвраты метода, кажется, то же самое как первый объект и не отражают новое значение поля. Я должен испытывать это поведение?
ObjectOutputStream class отслеживает каждый объект, это сериализирует и отправляет только дескриптор, если тот объект замечается снова. Это - способ, которым это имеет дело с графиками объектов. Соответствие ObjectInputStream отслеживает все объекты, которые это создало и их дескрипторы так, когда дескриптор замечается снова, это может возвратить тот же самый объект. И выходные и входные потоки сохраняют это состояние, пока они не освобождаются.
Альтернативно, ObjectOutputStream class реализует a reset метод, который отбрасывает память того, что отправил объект, таким образом отправляя объект снова, сделает копию.
9. Там какие-либо планы состоят в том, чтобы поддерживать сериализацию объектов потока?
Потоки НЕ будут сериализуемы. В существующей реализации, если Вы пытаетесь сериализировать и затем десериализовать поток, нет НИКАКОГО явного выделения нового собственного потока или стека; все, что происходит, - то, что объект является выделенными системными ресурсами ни с одной из собственной реализации. Короче говоря, это только не будет работать и перестанет работать непредсказуемыми способами.
Трудность с потоками состоит в том, что у них есть так много состояния, которое запутанно связывается в виртуальную машину, что это является трудным или невозможным восстановить контекст где-то в другом месте. Например, сохранение стека вызовов VM недостаточно потому что, если были собственные методы, которые вызвали процедуры C, которые поочередно вызывали код для платформы Java, будет невероятное соединение конструкций языка программирования Java и указателей C, чтобы иметь дело с. Кроме того, сериализация стека подразумевала бы сериализацию любого объекта, достижимого от любой переменной стека.
Если бы поток был возобновлен в том же самом VM, то он совместно использовал бы много состояния с исходным потоком, и поэтому перестал бы работать непредсказуемыми способами, если бы оба потока работали сразу, точно так же как два потока C, пытающиеся совместно использовать стек. Когда десериализовано в отдельном VM, трудно сказать то, что могло бы произойти.
10. Я могу вычислить разность (последовательный (x), последовательный (y))?
Разность произведет тот же самый поток каждый раз, когда тот же самый объект сериализируется. Вы должны будете создать новое ObjectOutputStream сериализировать каждый объект.
11. Я могу сжать последовательное представление своих объектов, используя мою собственную zip и разархивировать методы?
ObjectOutputStream производит OutputStream; если Ваш объект zip расширяется OutputStream class там не является никакой проблемой, сжимающей это.
12. Я могу выполнить методы на сжатых версиях моих объектов, например isempty (zip (последовательный (x)))?
Это не действительно жизнеспособно для произвольных объектов из-за кодирования объектов. Для определенного объекта (такого как Строка) можно сравнить получающиеся потоки битов. Кодирование устойчиво в тот каждый раз, когда тот же самый объект кодируется, это кодируется к тому же самому набору битов.
13. Если я пытаюсь сериализировать шрифт или объект изображения и затем попытаться воссоздать это в различном VM, мое приложение умирает. Почему?
Удаленный. Шрифты теперь сериализуемы, но изображения не.
14. Как я сериализирую дерево объектов?
Вот краткий пример, который показывает, как сериализировать дерево объектов.
import java.io.*;
class tree implements java.io.Serializable {
public tree left;
public tree right;
public int id;
public int level;
private static int count = 0;
public tree(int depth) {
id = count++;
level = depth;
if (depth > 0) {
left = new tree(depth-1);
right = new tree(depth-1);
}
}
public void print(int levels) {
for (int i = 0; i < level; i++)
System.out.print(" ");
System.out.println("node " + id);
if (level <= levels && left != null)
left.print(levels);
if (level <= levels && right != null)
right.print(levels);
}
public static void main (String argv[]) {
try {
/* Create a file to write the serialized tree to. */
FileOutputStream ostream = new FileOutputStream("tree.tmp");
/* Create the output stream */
ObjectOutputStream p = new ObjectOutputStream(ostream);
/* Create a tree with three levels. */
tree base = new tree(3);
p.writeObject(base); // Write the tree to the stream.
p.flush();
ostream.close(); // close the file.
/* Open the file and set to read objects from it. */
FileInputStream istream = new FileInputStream("tree.tmp");
ObjectInputStream q = new ObjectInputStream(istream);
/* Read a tree object, and all the subtrees */
tree new_tree = (tree)q.readObject();
new_tree.print(3); // Print out the top 3 levels of the tree
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
15. Если class A не реализует Serializable но подкласс B реализации Serializable, будут поля class A быть сериализированными, когда B будет сериализирован?
Только поля Serializable объекты выписываются и восстанавливаются. Объект может быть восстановлен, только если у class A есть конструктор без аргументов, который инициализирует поля несериализуемых супертипов. Если у подкласса есть доступ к состоянию суперкласса, это может реализовать writeObject и readObject сохранить и восстановить то состояние.