2009-01-22 118 views
2

我用java插座构建一个简单的客户端/服务器应用程序,并与用ObjectOutputStream试验等的Java socket编程

我一直在这个网址http://java.sun.com/developer/technicalArticles/ALT/sockets教程开始一半时以下时,谈到了运输物件插座。

看我的客户端代码http://pastebin.com/m37e4c577但是,这似乎并没有工作,我不明白什么是行不通的。在底部注释掉的代码直接从教程中复制出来 - 这在我刚刚使用该代码而不是创建客户端对象时起作用。

任何人都可以看到我做错了什么吗?

+0

您需要取消注释。哈认真,但编译错误是什么? – 2009-01-22 23:53:44

+0

有没有错误 - 它只是不工作与我未注释的代码,我不明白为什么?评论代码的作品 - 我刚分离,并把它放到一个实际的对象......这让我发疯。 – Malachi 2009-01-23 08:22:52

回答

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行来完成此操作。

5

你不在任何地方写对象。

再看到该链接,地方你必须写:

oos.writeObject(new Date()); 

在你的代码只有

ois.readObject(); 

这就是为什么

+0

发布的代码仅包含客户端,因此不需要编写对象。 – 2009-01-23 17:55:55

1

也许你会喜欢学习最基本第一。

下面是我刚刚编码的示例。

它开始服务器,只出席一个客户端,它发送一个对象和死亡。

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

这里没有例外。只是为了简化事情,但这不是应该处理异常的方式。

当你理解了这里的所有概念时,会更容易理解教程中的那些概念。

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

    } 
} 

我希望这会有所帮助。

1

如果您尝试调试它会告诉你哪里出了问题了。(也许不是为什么)

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

解决方案:始终首先创建ObjectOutputStream并在创建ObjectInputStream之前flush()它。

2

只是提醒。

当您使用ObjectOutputStream时请记住它保留了一个引用缓存。如果您编写一个对象,更改对象内容,然后再次发送相同的对象,您将获得重复的数据。例如:

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

将在客户端产生两个带有字符串“value1”的列表。

为了避免这种情况,复位方法必须调用同一个对象的引用多次写入时重置流缓存:

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

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