【问题标题】:Receive an object over TCP/IP通过 TCP/IP 接收对象
【发布时间】:2014-01-12 09:13:03
【问题描述】:

我要通过 TCP/IP 编写一个程序,我应该通过客户端或服务器发送对象,当我想发送或接收字符串但尝试读取对象时,它会正确:

private Socket client;

public ThreadedClient(Socket client) {
    this.client = client;
}

@Override
public void run() {
        try {
            ObjectInputStream objIn = new ObjectInputStream(client.getInputStream());
            while(true){
                try {
                    Object fromClient = objIn.readObject();

                } catch (ClassNotFoundException e) {e.printStackTrace();}
            }
        } catch (IOException e) {e.printStackTrace();}
    }

我收到一个异常:

java.io.StreamCorruptedException: invalid stream header: 306E6165
    at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
    at java.io.ObjectInputStream.<init>(Unknown Source)
    at org.bihe.serverSocket.ThreadedClient.run(Server.java:137)
    at java.lang.Thread.run(Unknown Source)

它指的是这一行:

    ObjectInputStream objIn = new ObjectInputStream(client.getInputStream());

这是我的服务器代码:

            ServerSocket ss = new ServerSocket(8800);
            while(true){
                Socket newClient = ss.accept();

                System.out.println(">>>> Client number " + (++counter) + " connected.");
                OutputStream outputStream = newClient.getOutputStream();
                PrintWriter sender = new PrintWriter(outputStream);
                sender.println(true);
                sender.flush();
                ThreadedClient client = new ThreadedClient(newClient);
                clients.add(client);
                new Thread(client).start();

客户端代码:

sc = new Socket("127.0.0.1", 8800);
            InputStream inputStream = sc.getInputStream();
            Scanner scanner = new Scanner(inputStream);
            boolean s = scanner.nextBoolean();
            if(s){
                System.out.println("Client connected successfully.");
                return true;
            }else{
                System.out.println("Ohhh, Some problem happened, try again later!");
            }

谁能解释一下发生了什么,这个异常是什么以及为什么我收到这个异常?

【问题讨论】:

  • 显示发射器代码。
  • 我从我的项目中添加了一些代码,你需要更多吗?

标签: java sockets tcp-ip objectinputstream


【解决方案1】:

如果你想通过网络发送对象,你必须序列化你的对象。

检查这个问题: How To send an object over TCP in Java

Java 序列化: Serialization

你可以这样做:

import java.net.*;  
import java.io.*;  

class testobject implements Serializable {  
  int value;  
  String id;  

  public  testobject(int v, String s ){  
       this.value=v;  
       this.id=s;  
    }  

}  

public class SimpleServer  {  
  public static void main(String args[]) {  
  int port = 2002;  
  try {  
    ServerSocket ss = new ServerSocket(port);  
    Socket s = ss.accept();  
    InputStream is = s.getInputStream();  
    ObjectInputStream ois = new ObjectInputStream(is);  
    testobject to = (testobject)ois.readObject();  
    if (to!=null){System.out.println(to.id);}  
    System.out.println((String)ois.readObject());  
    is.close();  
    s.close();  
    ss.close();  
}catch(Exception e){System.out.println(e);}  
}  
}  

import java.net.*;  
import java.io.*;  
   public class SimpleClient {  
   public static void main(String args[]){  
     try{  
     Socket s = new Socket("localhost",2002);  
     OutputStream os = s.getOutputStream();  
     ObjectOutputStream oos = new ObjectOutputStream(os);  
     testobject to = new testobject(1,"object from client");  
     oos.writeObject(to);  
     oos.writeObject(new String("another object from the client"));  
     oos.close();  
     os.close();  
     s.close();  
   }catch(Exception e){System.out.println(e);}  
  }  
}  

【讨论】:

  • 这里没有证据表明正在发送的对象是不可序列化的。
  • 我想发送一个实现可序列化并具有serialversionUID的客户端,在某些情况下我想向服务器发送一个字符串,但它不会在ObjectInputStream objIn = new ObjectInputStream( client.getInputStream());我认为这与可序列化无关,我了解您的代码,但我不明白为什么会收到此异常。
  • @AttilaBujáki 你没有回答我的问题,但你的代码很有帮助,我感谢你的时间
【解决方案2】:

只需摆脱发送和接收布尔值。这是多余的。如果创建连接时出现问题,则不会创建套接字:而是会引发异常。您将所有内容与同一个套接字上的多个流混淆了。不要那样做。

在你的读取对象循环中,你需要单独捕获 EOFException,当你得到它时,关闭套接字并退出循环。如果你得到任何其他 IOException,记录它,关闭套接字,然后退出循环。

【讨论】:

  • 我发现了我的问题,你是对的,我删除了不需要的代码,所以我理解了这个问题。这是因为我试图通过 printwriter 发送一个字符串,但是当我更改代码时,我试图通过 objectInputStream 接收该字符串并导致异常,我将 printwriter 更改为 objectOutputStream 并且问题解决了,谢谢大家,但是我不明白你为什么说当我得到 EOFException 时我应该关闭循环,我有一个像 twitter 这样的项目,而我正处于起点。我应该在客户端运行时发送和接收对象,为什么要关闭套接字?
  • 1.不,这是因为您在同一个套接字上使用了多个流,只有在没有缓冲的情况下才有效……但这仍然不是一个好主意。 2. 当您收到 EOFException 时,表示对等方已关闭连接。没有更多的数据了。永远不会有更多的数据。如果你继续阅读,你只会不断收到 EOFException。别。跳出循环。
  • 第一部分,我该怎么做?您是说通过 arraylist 并通过 objectOutputStream 发送我想要的所有内容不是一个好主意,然后我捕获 arrayList 的第一个成员,它是一个字符串,并通过它的值发送可能是客户端的第二个成员或在服务器端做某事的字符串?你有更好的主意吗?对于第二部分:我明白了,谢谢,这意味着客户端退出了,所以我应该关闭套接字,对吗?
  • 1.我说了我说的话。摆脱发送和接收布尔值。摆脱ScannerPrintWriter. 通过单个流执行所有操作。 2. 我确实多次提到关闭套接字。
【解决方案3】:

如果您想获得良好的性能并发送对象,那么您绝对应该使用Google Protobuf

它允许您在简单的 .proto 文件中定义消息。然后使用捆绑编译器生成 Java 类,这些类将被序列化并发送。

另外一个更好的主意是在普通的 Java 套接字上使用 Netty。这可以防止您编写大量样板代码并定义简单的序列化/反序列化管道。看看user-guide

【讨论】:

  • 不回答问题。 OP 没有表示他对不断变化的技术持开放态度。
  • 因为也许他不知道任何替代方案。我的解决方案更易于实施并且性能更好。
  • OP 没有表明他甚至在寻找替代方案。您的解决方案实际上并不能解决问题。这里没有证据表明您甚至知道问题所在。
  • 我不知道您指的是什么“消息”,但如果您想知道问题所在,请参阅我的回答。
  • 好的 - 现在我知道你改变了你的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 2013-07-13
  • 2012-09-27
  • 2017-01-13
  • 1970-01-01
相关资源
最近更新 更多