我正在使用java套接字构建一个简单的客户端/服务器应用程序,并尝试使用ObjectOutputStream等。
当我讨论通过套接字传输对象时,我一直在这个url http://java.sun.com/developer/technicalArticles/ALT/sockets开始关注教程。
请参阅我的客户端代码http://pastebin.com/m37e4c577但是这似乎不起作用,我无法弄清楚什么不起作用。底部注释掉的代码直接从教程中复制出来 - 当我只使用它而不是创建客户端对象时,这就有效。
任何人都可以看到我做错了吗?
答案 0 :(得分: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行即可完成此操作。
答案 1 :(得分:5)
你不是在任何地方写这个对象。
再次看到那个链接,你必须写的地方:
oos.writeObject( new Date() );
在您的代码中,您只有
ois.readObject();
这就是为什么
答案 2 :(得分: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);
答案 3 :(得分:1)
你可能想先学习最基本的东西。
这是我刚刚编写的一个示例。
它启动服务器,只参加一个客户端,然后发送一个对象并死掉。
当用户(您)按Enter键时,将创建一个新的客户端,它将连接到先前创建的服务器并读取服务器将发送的对象。
这里没有处理任何异常。只是为了使事情更简单,但这不是处理异常的方式。
当您理解了这里的所有概念时,将更容易理解教程中的那些概念。
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();
}
}
我希望这会有所帮助。
答案 4 :(得分:1)
如果您尝试使用调试器,它会告诉您问题出在哪里。(也许不是原因)
您遇到的问题是ObjectOutputStream写入标头,ObjectInputStream读取该标头。您首先创建了ObjectInputStream,这意味着它正在尝试读取永远不会被写入的标头。
解决方案:首先创建ObjectOutputStream并在创建ObjectInputStream之前刷新()它。
答案 5 :(得分:1)
打开outputStream
会更好,因为输出流不会阻止。然后,您有一个等待Stream
的输入流。在所有流之后,您写入流并刷新它 - outputStream.flush()
以发送数据字节。您还需要另一端的方法来读取输入,无论它是inputStream.read()
只读取每个字节作为char
的整数,还是使用{ {1}}或BufferedReader
。我几乎使用了所有可能的方法,但最有效的发送方法是Scanner
,它将outputStream.write(String)
s的序列写为char
s并读取{{1}读取单个byte
。我希望这会有所帮助。