Вопрос

Я создаю простое клиент-серверное приложение с использованием Java-сокетов и экспериментирую с ObjectOutputStream и т. д.

Я следую учебному пособию по этому URL-адресу http: //java.sun .com / developer / technicalArticles / ALT / sockets начинается с половины пути, когда речь идет о переносе объектов через сокеты.

См. мой код для клиента. http: // pastebin. com / m37e4c577 Однако, похоже, это не работает, и я не могу понять, что не работает. Код, закомментированный внизу, напрямую копируется из учебника - и это работает, когда я просто использую его вместо создания объекта client.

Кто-нибудь может увидеть, что я делаю не так?

Это было полезно?

Решение

Проблема в том, что вы создаете потоки.

На сервере из статьи (который, я предполагаю, используется вами), когда открывается новое соединение, сервер сначала открывает входной поток, а затем выходной поток:

public Connect(Socket clientSocket) {
 client = clientSocket;
 try {
  ois = new ObjectInputStream(client.getInputStream());
  oos = new ObjectOutputStream(client.getOutputStream());
 } catch(Exception e1) {
     // ...
 }
 this.start();
}

В примере кода с комментариями используется обратный порядок, сначала устанавливается выходной поток, затем входной поток:

// open a socket connection
socket = new Socket("localhost", 2000);
// open I/O streams for objects
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());

Но ваш код делает это наоборот:

server = new Socket(host, port);
in = new ObjectInputStream(server.getInputStream());
out = new ObjectOutputStream(server.getOutputStream());

Создание пары выходной поток / входной поток будет зависать до тех пор, пока они не обменяются информацией о квитировании, поэтому вы должны соответствовать порядку создания. Вы можете сделать это, просто поменяв строки 34 и 35 в вашем примере кода.

Другие советы

Вы нигде не пишете объект.

Посмотрите эту ссылку еще раз, где-то, что вы должны написать:

 oos.writeObject( new Date() );

В вашем коде есть только

ois.readObject();

Вот почему

Просто напоминание.

Когда вы используете ObjectOutputStream, имейте в виду, что он хранит кеш ссылок. Если вы напишите объект, измените его содержимое, а затем снова отправите тот же объект, вы получите дублированные данные. Например:

List list = new ArrayList();
list.add("value1");
out.writeObject(list);
list.clear();
list.add("value2");
out.writeObject(list);

Создает на стороне клиента два списка со строкой " value1 ".

Чтобы избежать этого, необходимо вызвать метод reset для сброса потокового кэша при многократной записи одной и той же ссылки на объект:

List list = new ArrayList();
list.add("value1");
out.writeObject(list);
out.reset();
list.clear();
list.add("value2");
out.writeObject(list);

Вероятно, вы сначала захотите изучить самое основное.

Вот пример, который я только что написал.

Он запускает сервер , который посещает только ОДИН клиент, и отправляет объект и умирает.

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

Здесь исключение не обрабатывается. Просто для упрощения, но это НЕ тот способ, которым нужно обрабатывать исключения.

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

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

public class SimpleServer implements Runnable { 

     // Creates the server, send a "date" and die.
    public void run() { 
        try {
            ServerSocket server = new ServerSocket( 8090 );
            Date creationDate = new Date();
            System.out.println("(Server) Server is ready " 
                                 + "and running at " + creationDate );

            Socket uniqueClient = server.accept();

            // We will write using this "chained" object.
            ObjectOutputStream out = new ObjectOutputStream( 
                                                 uniqueClient.getOutputStream());

            out.writeObject( creationDate );


            // close all, at this point forget about the exceptions.
            // this is lesson #1      
            out.close();

            uniqueClient.close();

            server.close();        

            System.out.println("(Server) The server is down");
        }catch( IOException ioe ) {}

     }

    public static void main ( String [] args ) throws IOException ,
                                                 ClassNotFoundException { 

         Thread serverThread = new Thread( new SimpleServer() );

         serverThread.start(); // start the server thread ... doh..

         System.out.println("(Client) Press enter when you want "+ 
                               " to connect to the server...");

         Scanner scanner = new Scanner( System.in );

         scanner.nextLine();

         Socket client = new Socket("localhost", 8090 );

         // Read from this object.
         ObjectInputStream in = new ObjectInputStream( client.getInputStream() );

         Date date = ( Date ) in.readObject();

         System.out.println("(Client) Current time is:          " + new Date() );
         System.out.println("(Client) Object read from server : " + date );

         in.close();
         client.close();

    }
}

Надеюсь, это поможет.

Если бы вы попробовали отладчик, он бы сказал вам, где проблема. (Возможно, не почему)

Проблема в том, что ObjectOutputStream записывает заголовок, а ObjectInputStream читает этот заголовок. Сначала вы создали ObjectInputStream, что означает, что он пытается прочитать заголовок, который никогда не будет записан.

Решение: всегда сначала создавайте ObjectOutputStream и очищайте его () перед созданием ObjectInputStream.

Лучше открыть outputStream, потому что выходной поток не блокируется. Затем у вас есть входной поток, который ожидает Stream. После всех потоков вы пишете в поток и очищаете его - outputStream.flush() для отправки байтов данных. Вам также понадобится метод на другом конце для чтения ввода, будь то просто inputStream.read(), который читает каждый байт как целое число для char, или используя BufferedReader или Scanner. Я использовал почти все возможные методы, но самый эффективный метод для отправки - это outputStream.write(String), который записывает последовательность byte в виде <=> в поток, а чтение <=> читает один <=>. Надеюсь, это поможет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top