4

我正在使用 java 套接字构建一个简单的客户端/服务器应用程序并尝试使用 ObjectOutputStream 等。

当它谈到通过套接字传输对象时,我一直在关注这个 url http://java.sun.com/developer/technicalArticles/ALT/sockets上的教程。

请参阅我的客户端代码http://pastebin.com/m37e4c577但是这似乎不起作用,我无法弄清楚什么不起作用。底部注释掉的代码是直接从教程中复制出来的——当我只使用它而不是创建客户端对象时,这很有效。

谁能看到我做错了什么?

4

6 回答 6

7

问题是您创建流的顺序:

在文章中的服务器(我假设您正在使用的服务器)中,当打开新连接时,服务器首先打开一个输入流,然后打开一个输出流:

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 行来做到这一点。

于 2009-01-23T12:01:15.823 回答
5

您没有在任何地方写对象。

再次查看该链接,您必须在某处写:

 oos.writeObject( new Date() );

在您的代码中,您只有

ois.readObject();

这就是为什么

于 2009-01-22T23:59:18.277 回答
2

可能你会想先学习最基本的。

这是我刚刚编码的示例。

它启动一个服务器,它只参与一个客户端,它发送一个对象并死掉。

当用户(你)按下回车键时,一个新的客户端被创建,它连接到先前创建的服务器并读取服务器将发送的对象。

这里不处理任何异常。只是为了让事情更简单,但这不是处理异常的方式。

当您理解了这里的所有概念后,将更容易理解本教程中的那些概念。

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

    }
}

我希望这有帮助。

于 2009-01-23T00:31:29.490 回答
2

如果您尝试使用调试器,它会告诉您问题出在哪里。(也许不是为什么)

您遇到的问题是 ObjectOutputStream 写入了一个标头,而 ObjectInputStream 读取了该标头。您首先创建了 ObjectInputStream,这意味着它正在尝试读取一个永远不会被写入的标头。

解决方案:始终先创建 ObjectOutputStream,然后在创建 ObjectInputStream 之前对其进行 flush()。

于 2009-01-23T07:22:29.333 回答
2

只是提醒。

当您使用 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);
于 2009-01-23T11:37:31.347 回答
2

最好打开一个,outputStream因为输出流不会阻塞。然后,您有等待Stream. 在所有流之后,您写入流并刷新它 -outputStream.flush()以发送数据字节。您还需要在另一端有一个方法来读取输入,无论是简单地inputStream.read()将每个字节读取为 a 的整数char,还是使用 aBufferedReaderScanner。我已经使用了几乎所有可能的方法,但最有效的发送方法是将soutputStream.write(String)的序列写入流中,读取读取单个. 我希望这有帮助。charbyteinputStream.read()char

于 2014-10-07T05:42:51.863 回答