Java Socket Программирование - PullRequest
3 голосов
/ 23 января 2009

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

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

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

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

Ответы [ 6 ]

7 голосов
/ 23 января 2009

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

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

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 в вашем примере кода.

5 голосов
/ 23 января 2009

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

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

 oos.writeObject( new Date() );

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

ois.readObject();

Вот почему

2 голосов
/ 23 января 2009

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

Когда вы используете 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);
1 голос
/ 07 октября 2014

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

1 голос
/ 23 января 2009

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

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

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

1 голос
/ 23 января 2009

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

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

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

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

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

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

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();

    }
}

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

...