ObjectInputStream 总是检索一个空列表
ObjectInputStream always retrieves a empty List
我正在处理一个客户端-服务器项目(您可以称它为 "Broadcast Chat"),但我遇到了 ObjectInputStream 的问题。
它总是给我检索一个空列表,我找到了一个解决方案,但我不知道它为什么有效...
这是错误代码(检查服务器的 sendMsg() 函数):
服务器:
public class CoreServer implements Runnable {
private Socket sock;
private ServerConnect sc;
private ObjectOutputStream oos;
private ObjectInputStream ois;
private boolean running=true;
private List<String> lstr;
public CoreServer(Socket sock, ServerConnect sc) {
this.sock=sock;
this.sc=sc;
}
@Override
public void run() {
lstr=new LinkedList<String>();
try {
oos= new ObjectOutputStream(sock.getOutputStream());
ois=new ObjectInputStream(sock.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
while (running){
Object o=null;
try {
o= ois.readObject();
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
sc.remove(this);
stop();
}
if (Integer.class.isInstance(o)){
try {
int num= (Integer) o;
if(num==0){
sendMsg();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if (String.class.isInstance(o)){
System.out.println("String Received");
String ss= (String) o;
sc.readyToSend(ss);
}
}
}
public void sendMsg() throws IOException{
try {
System.out.println("I'm going to send: "+lstr);
oos.writeObject((Object)lstr);
oos.flush();
lstr.clear();
// If I replace lstr.clear() with "lstr=new LinkedList();" it works as it should.
} catch (IOException e) {
e.printStackTrace();
}
}
public void addMsg(String text){
System.out.println("I will add -"+text+"- to the list");
lstr.add(text);
}
}
客户:
public class ClientConnect implements Runnable {
private Socket sock;
private boolean running=true;
private ObjectInputStream ois;
private ObjectOutputStream oos;
private boolean first=true;
private Object o;
private ClientFrame cf;
public ClientConnect(Socket sock, ClientFrame cf){
this.sock=sock;
this.cf=cf;
}
@Override
public void run() {
if (first){
try {
oos= new ObjectOutputStream(sock.getOutputStream());
ois= new ObjectInputStream(sock.getInputStream());
first=false;
} catch (IOException e) {
e.printStackTrace();
}
}
while (running){
try {
oos.writeObject(new Integer(0));
oos.flush();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Connection error");
this.stop();
System.exit(1);
}
try {
o=ois.readObject();
System.out.println("I received o : "+(List)o);
} catch (ClassNotFoundException | IOException e) {
JOptionPane.showMessageDialog(null, "Server offline");
System.exit(1);
}
if(List.class.isInstance(o)){
List<String> l=null;
l=(List<String>) o;
Iterator<String> it= l.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println("Adding:"+s);
cf.history.append(s+ "\n"); //this function will show the received content on a JTextArea
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void send(String text){
if (!text.equals("")){
try {
oos.writeObject(text);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端应该将我写的东西发送到服务器,然后服务器将向每个连接的客户端发送相同的消息。
这是我写东西时服务器端和客户端发生的情况:
服务器日志:
Waiting client
Found one client
Waiting client //The Server is multithreaded and is waiting for another client to connect
Waiting client
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Hello- to the list
I'm going to send: [Hello]
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Whosebug- to the list
I'm going to send: [Whosebug]
I'm going to send: []
I'm going to send: []
I'm going to send: []
I'm going to send: []
客户端日志:
I received o : []
I received o : []
I received o : []
You wrote: Hello
I received o : [] <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []
You wrote: Whosebug
I received o : [] <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []
I received o : []
如果我将 sendMsg() 中的 lstr.clear() 替换为 "lstr=new LinkedList();",它会正常工作,但我不知道为什么 :(
客户端日志(修复后):
I received o : []
I received o : []
I received o : []
You wrote: Hello
I received o : [Hello]
Adding:Hello
I received o : []
I received o : []
I received o : []
You wrote: Whosebug
I received o : [Whosebug]
Adding:Whosebug
I received o : []
I received o : []
I received o : []
I received o : []
如何解释这种行为?
序列化协议保留对象身份。
如果您重复写入同一个对象,它不会再次序列化其内容,流将只包含一个反向引用以指示您再次写入同一个对象。
因此,流将仅包含列表在您首次发送时的状态,即为空。
当您稍后将内容添加到列表并再次编写列表时,不会被拾取。该流将只包含一个标签,上面写着 "that list from before again".
当您从 list.clear()
更改为创建一个全新的列表实例时,您解决了这个问题:现在,每个列表都在写入时连同其数据一起写入流中。
我正在处理一个客户端-服务器项目(您可以称它为 "Broadcast Chat"),但我遇到了 ObjectInputStream 的问题。 它总是给我检索一个空列表,我找到了一个解决方案,但我不知道它为什么有效...
这是错误代码(检查服务器的 sendMsg() 函数):
服务器:
public class CoreServer implements Runnable {
private Socket sock;
private ServerConnect sc;
private ObjectOutputStream oos;
private ObjectInputStream ois;
private boolean running=true;
private List<String> lstr;
public CoreServer(Socket sock, ServerConnect sc) {
this.sock=sock;
this.sc=sc;
}
@Override
public void run() {
lstr=new LinkedList<String>();
try {
oos= new ObjectOutputStream(sock.getOutputStream());
ois=new ObjectInputStream(sock.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
while (running){
Object o=null;
try {
o= ois.readObject();
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
sc.remove(this);
stop();
}
if (Integer.class.isInstance(o)){
try {
int num= (Integer) o;
if(num==0){
sendMsg();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if (String.class.isInstance(o)){
System.out.println("String Received");
String ss= (String) o;
sc.readyToSend(ss);
}
}
}
public void sendMsg() throws IOException{
try {
System.out.println("I'm going to send: "+lstr);
oos.writeObject((Object)lstr);
oos.flush();
lstr.clear();
// If I replace lstr.clear() with "lstr=new LinkedList();" it works as it should.
} catch (IOException e) {
e.printStackTrace();
}
}
public void addMsg(String text){
System.out.println("I will add -"+text+"- to the list");
lstr.add(text);
}
}
客户:
public class ClientConnect implements Runnable {
private Socket sock;
private boolean running=true;
private ObjectInputStream ois;
private ObjectOutputStream oos;
private boolean first=true;
private Object o;
private ClientFrame cf;
public ClientConnect(Socket sock, ClientFrame cf){
this.sock=sock;
this.cf=cf;
}
@Override
public void run() {
if (first){
try {
oos= new ObjectOutputStream(sock.getOutputStream());
ois= new ObjectInputStream(sock.getInputStream());
first=false;
} catch (IOException e) {
e.printStackTrace();
}
}
while (running){
try {
oos.writeObject(new Integer(0));
oos.flush();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Connection error");
this.stop();
System.exit(1);
}
try {
o=ois.readObject();
System.out.println("I received o : "+(List)o);
} catch (ClassNotFoundException | IOException e) {
JOptionPane.showMessageDialog(null, "Server offline");
System.exit(1);
}
if(List.class.isInstance(o)){
List<String> l=null;
l=(List<String>) o;
Iterator<String> it= l.iterator();
while (it.hasNext()){
String s=it.next();
System.out.println("Adding:"+s);
cf.history.append(s+ "\n"); //this function will show the received content on a JTextArea
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void send(String text){
if (!text.equals("")){
try {
oos.writeObject(text);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端应该将我写的东西发送到服务器,然后服务器将向每个连接的客户端发送相同的消息。 这是我写东西时服务器端和客户端发生的情况:
服务器日志:
Waiting client
Found one client
Waiting client //The Server is multithreaded and is waiting for another client to connect
Waiting client
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Hello- to the list
I'm going to send: [Hello]
I'm going to send: []
I'm going to send: []
I'm going to send: []
String Received
I will add -Whosebug- to the list
I'm going to send: [Whosebug]
I'm going to send: []
I'm going to send: []
I'm going to send: []
I'm going to send: []
客户端日志:
I received o : []
I received o : []
I received o : []
You wrote: Hello
I received o : [] <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []
You wrote: Whosebug
I received o : [] <-- it can't read the list that the server sent to me.
I received o : []
I received o : []
I received o : []
I received o : []
如果我将 sendMsg() 中的 lstr.clear() 替换为 "lstr=new LinkedList();",它会正常工作,但我不知道为什么 :(
客户端日志(修复后):
I received o : []
I received o : []
I received o : []
You wrote: Hello
I received o : [Hello]
Adding:Hello
I received o : []
I received o : []
I received o : []
You wrote: Whosebug
I received o : [Whosebug]
Adding:Whosebug
I received o : []
I received o : []
I received o : []
I received o : []
如何解释这种行为?
序列化协议保留对象身份。
如果您重复写入同一个对象,它不会再次序列化其内容,流将只包含一个反向引用以指示您再次写入同一个对象。
因此,流将仅包含列表在您首次发送时的状态,即为空。
当您稍后将内容添加到列表并再次编写列表时,不会被拾取。该流将只包含一个标签,上面写着 "that list from before again".
当您从 list.clear()
更改为创建一个全新的列表实例时,您解决了这个问题:现在,每个列表都在写入时连同其数据一起写入流中。