【问题标题】:JAVA send Scribble over networkJAVA通过网络发送Scribble
【发布时间】:2013-11-09 03:59:06
【问题描述】:

我正在为学校做一个项目,我正在使用插座制作一个图画游戏。对于图像的绘制,我找到了this 代码。我想使用版本 3,因为我不需要数字等所有功能。

现在,我的套接字已正确设置,但不幸的是,使用的 ScribbleCanvas(来自上面的链接)不可序列化(或者看起来就是这样)。有没有办法让它像这样,或者通过ObjectOutputStream发送它?速度应该不是真正的问题,因为它只应该在本地工作,目前在 localhost 上进行测试,所以它不应该是最有效的方式。

编辑:我已经对错误所在的程序做了一个快速模型,也许我在其他地方犯了一些错误。

import java.awt.BorderLayout;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JPanel;

import scribble3.ScribbleCanvas;

public class Main extends JFrame{
    /* Scribble */
    public static ScribbleCanvas myCanvas;
    public static JPanel scribblePanel;

    /* TCP */
    public static ServerSocket hostServer;
    public static Socket socket;
    public static OutputStream os;
    public static InputStream is;
    public static ObjectInputStream ois;
    public static ObjectOutputStream oos;

    /* Panels & Frames */
    public static JFrame mainFrame;
    public static JPanel menuPanel;
    public static JPanel mainPane;

    /* Ohter */
    public static boolean isHost = true; // is this instance a host or not?
    public final static int DISCONNECTED = 0;
    public final static int CONNECTING = 1;
    public final static int CONNECTED = 2;
    public static int connectionStatus = CONNECTING;

    public static void initGUI(){
        menuPanel = new JPanel();
        //menuPanel = getMenu(); // some menu items

        scribblePanel = new JPanel(new BorderLayout());
        myCanvas = new ScribbleCanvas();
        scribblePanel.add(myCanvas);

        mainPane = new JPanel(new BorderLayout());
        mainPane.add(menuPanel, BorderLayout.WEST);
        mainPane.add(scribblePanel, BorderLayout.CENTER);

        mainFrame = new JFrame("Pictionary");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setBounds(200, 200, 800, 500);
        mainFrame.setContentPane(mainPane);
        mainFrame.setVisible(true);
    }

    public static void main(String[] args) {
        initGUI();

        while(true){
            switch(connectionStatus){
            case DISCONNECTED:

                break;
            case CONNECTING:
                try{
                    if(isHost){ // You are a host
                        hostServer = new ServerSocket(5454);
                        socket = hostServer.accept();
                    }else{      // You're not a host
                        socket = new Socket("localhost", 5454);
                    }

                    os = socket.getOutputStream();
                    oos = new ObjectOutputStream(os);
                    is = socket.getInputStream();
                    ois = new ObjectInputStream(is);
                    oos.flush();

                    connectionStatus = CONNECTED;
                }catch(IOException e){
                    connectionStatus = DISCONNECTED;
                }
                break;
            case CONNECTED:
                if(isHost){
                    try {
                        oos.writeObject(scribblePanel);
                        //oos.writeObject(myCanvas);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }else{
                    try {
                        scribblePanel = (JPanel) ois.readObject();
                        //myCanvas = (ScribbleCanvas) ois.readObject();
                        mainFrame.repaint();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
            }
        }
    }
}

这是该程序的精简版,但它可以工作。如果您使用isHost = true; 运行一次,然后使用isHost = false; 运行一次,它们有一个连接,但随后我收到以下错误:java.io.NotSerializableException: scribble3.ScribbleCanvasListener,同时发送JPanelScribbleCanvas

java.io.NotSerializableException: scribble3.ScribbleCanvasListener
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at domain.Main.main(Main.java:102)

第 102 行引用 oos.writeObject(myCanvas)oos.writeObject(myScribble)

【问题讨论】:

  • 不可序列化?这很奇怪......根据另一个 StackOverflow 问题,所有 JComponents 都是可序列化的。从那篇文章来看,您使用的是哪个版本的课程?
  • @RobinGreen:查看我所做的编辑。我尝试仅发送 ScribbleCanvas 元素以及它所在的 JPanel 元素,但都给出了相同的错误。
  • NotSerializableException 的完整堆栈跟踪是什么?
  • @RobinGreen:我想我已经添加了你的要求。

标签: java sockets serialization objectoutputstream


【解决方案1】:

当它尝试写入某些字段时会出现问题。 ScribbleCanvas 的字段之一不可序列化。

我查看了所有字段,并注意到哪个字段包含不可序列化的对象。是听者。您需要使侦听器类可序列化。

【讨论】:

  • 那么ScribbleCanvas 的监听器目前还不能序列化?是否可以选择从接收者的类中删除此信息?接收者应该“只”接收绘图,并且不需要能够绘图。但我想这意味着让一个类基本相同,但没有听众,并且能够以某种方式从一个转换到另一个?
  • 好主意!实际上,不,没有必要 - 只需将 transient 添加到侦听器变量中,这将防止它被序列化。
  • @arbitter 这是因为当您使用新对象重新分配变量时,旧对象不会更新。 Swing 仍然具有对旧对象的引用。你需要在反序列化之前mainPane.remove(scribblePanel),然后在反序列化之后再次mainPane.add(scribblePanel, BorderLayout.CENTER)
  • 我使用了mainFrame.repaint(),但我想这并没有成功。但是使用.remove().add() 似乎仍然不起作用。我一直在阅读 Scribble 的代码,显然每个点都以Point 的形式存储在Stroke 中。也许单独发送点并调整 Scribble 的代码以插入接收到的点并绘制它们会更快,而不是每次都发送整个属性集?
  • 我现在不是通过网络发送整个Scribble,而是通过网络发送每个Stroke,它似乎工作得很快!然后我添加了一些方法来添加新的笔画(对于接收者)和发送笔画(发送者),只需要重构和编辑Scribble的代码就可以了。谢谢!
猜你喜欢
  • 2015-02-19
  • 1970-01-01
  • 2011-04-05
  • 2017-08-02
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多