SocketException: сброс соединения на сервере с ObjectInputStream

Я пытаюсь понять ObjectInputStream/ObjectOutputStream, поэтому я создаю очень простое серверно-клиентское приложение, в котором клиент отправляет объект HashMap по созданному потоку, а сервер получает его и печатает. вне.

Это мой код сервера:

import java.io.*;
import java.net.*;

public class Server {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ServerSocket server = new ServerSocket(4444);
        while (true) {
            Socket socket = server.accept();
            ObjectInputStream objIn = new ObjectInputStream(socket.getInputStream());

            if (objIn.readObject() != null) {
                System.out.println(objIn.readObject());
            }
        }    
    }
}

Это мой клиентский код:

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.HashMap;

public class Client {

    public static void main(String[] args) throws IOException {
        Socket sock;
        int port = 4444;
        HashMap<Integer, String>  mapSend= new HashMap<>();
        mapSend.put(1,"row1");
        mapSend.put(2,"row2");

        sock = new Socket(InetAddress.getLocalHost(), port);
        ObjectOutputStream objOut = new ObjectOutputStream(sock.getOutputStream());

        objOut.writeObject(mapSend);
        objOut.flush();
    }
}

Я запускаю файл сервера, и он работает нормально.
Затем я запускаю файл клиента и получаю следующую ошибку на сервере:

    Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:189)
    at java.net.SocketInputStream.read(SocketInputStream.java:121)
    at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2308)
    at java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:2716)
    at java.io.ObjectInputStream$BlockDataInputStream.readFully(ObjectInputStream.java:2740)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1978)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:499)
    at java.util.HashMap.readObject(HashMap.java:1115)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1891)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at iotest.Server.main(Server.java:17)
Java Result: 1

P.S. Я не знаю, нужно ли мне что-то делать для сериализации HashMap, но я думаю, что где-то видел, что это обрабатывается внутри Java. Я могу ошибаться.

ИЗМЕНИТЬ после ответа Аарона Я реализовал эту часть на своем сервере, как предложил Аарон:

Object objRead=objIn.readObject();
            if (objRead != null) {
                System.out.println(objRead);
            }

и теперь я получаю эту ошибку, снова с сервера, после запуска клиента:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:189)
    at java.net.SocketInputStream.read(SocketInputStream.java:121)
    at java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2308)
    at java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:2716)
    at java.io.ObjectInputStream$BlockDataInputStream.readFully(ObjectInputStream.java:2740)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1978)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1913)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at java.util.HashMap.readObject(HashMap.java:1154)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1891)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
    at iotest.Server.main(Server.java:17)
Java Result: 1

person akafortes    schedule 22.09.2013    source источник


Ответы (2)


Вы читаете объект дважды, но печатаете только во второй раз. Таким образом, клиент, вероятно, отключится к тому времени, когда вы попытаетесь прочитать второй раз, и поэтому сокет был закрыт на удаленном конце, следовательно, исключение.

Вы читаете объект при проверке != null. Вы его не печатаете. Затем вы пытаетесь прочитать это снова, и это бомбит.

Как только вы читаете из потока, он был прочитан. Это поток, а не буфер. Возможно, вы захотите буферизовать чтение, а затем можете проверять этот буфер сколько угодно.

Самый простой пример...

Object o = outputStream.readObject();
if(o != null) {
 system.out.println(o);
}
person Aaron    schedule 22.09.2013
comment
да. Главное помнить, что поток не буферизуется. Как только вы прочитали это, это исчезло. - person Aaron; 22.09.2013
comment
Случайно удалил свой комментарий. Большое спасибо за разъяснения. - person akafortes; 22.09.2013
comment
@akafortes Например, когда вы открываете пивной кран — вы можете открыть пиво, чтобы посмотреть, осталось ли пиво, но если вы не поймаете пролитое пиво в стакан, вы не сможете сказать «отлично», пиво есть в наличии, а затем попробовать пить пиво, которое вы уже пролили во время тестирования, если оно доступно. - person Aaron; 22.09.2013
comment
предполагается, что outputStream такой или это опечатка, и вы хотели написать inputStream? - person akafortes; 22.09.2013
comment
@akafortes да, извините. Входной поток. - person Aaron; 22.09.2013
comment
Я обновил свой вопрос, попробовав то, что вы предложили. Я все еще получаю сообщение об ошибке сброса соединения, но некоторые строки там другие. Не могли бы вы взглянуть еще раз, пожалуйста? - person akafortes; 22.09.2013
comment
Я скопировал/вставил ваш код, изменив сервер так, чтобы он выглядел так: while (true) { Socket socket = server.accept(); ObjectInputStream objIn = новый ObjectInputStream (socket.getInputStream()); Объект objRead=objIn.readObject(); if (objRead!= null) { System.out.println(objRead); } } и у меня это отлично работает :s - person Aaron; 22.09.2013
comment
Хорошо, я только что попробовал его в режиме отладки, и теперь он работает правильно, когда я запускаю файлы. Я понятия не имею, почему это работает сейчас: s В любом случае, еще раз спасибо, Аарон. - person akafortes; 22.09.2013
comment
Нулевой тест бессмыслен. Он не возвращает ноль, если вы не написали ноль. - person user207421; 23.09.2013

Это происходит потому, что клиентский сокет автоматически завершается после выполнения всего его кода.

Например, если вы добавите

while (true) {
    System.out.println("no operation");
    try {
        Thread.sleep(10000);
    } catch(InterruptedException e) {
        e.printStackTrace();
    }
}

в конце вашего клиентского кода вы не получите никакого сброса соединения, потому что ваш клиентский сокет никогда не будет завершен.

Таким образом, сокет на стороне клиента закрыт, и сокет на стороне сервера должен обрабатывать это исключение. Вы должны просто выйти из цикла, когда получите это исключение, поэтому:

boolean connected = true;
while (connected) {
    try {
        //your code
    } catch (SocketException e) {
        connected = false;
    }
}
person Cristian Traìna    schedule 19.04.2015