简体   繁体   English

使用套接字和线程发送和接收对象无法正常工作

[英]Sending and receiving objects using sockets and threads not working properly

I am currently creating a service allowing to send objects from a client to a server and vice-versa, but experiencing an issue that I unfortunately cannot explain and fix. 我目前正在创建一项服务,该服务允许将对象从客户端发送到服务器,反之亦然,但是遇到一个我不幸无法解释和解决的问题。

First of all, here are the useful classes (I haven't put all methods such as getters and setters in this post). 首先,这里是有用的类(在这篇文章中,我没有放置所有方法,例如getter和setter)。


/**
 * This launcher creates a NetworkInterface, waits for a connection, sends a message to the connected client and waits for an incoming message
 *
 */
public class ServerLauncher {

    public static void main(String[] args) {
        try {
            NetworkSystem n = new NetworkSystem(4096);
            n.startServerManager();

            while (n.getCommunications().isEmpty()) {
                // this line is unexpectedly magic
                System.out.println("Waiting for a new connection...");
            }

            do {
                n.getCommunications().get(0).send(new String("Hello, are you available?")); 
            } while (n.getCommunications().get(0).getReceiveManager().getReadObjects().isEmpty());

            System.out.println(n.getCommunications().get(0).getReceiveManager().getReadObjects().get(0));

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * This launcher creates a NetworkSystem, connects to the server, waits for an incoming message and anwers back
 *
 */
public class ClientLauncher {

    public static void main(String[] args) {
        try {
            NetworkSystem n = new NetworkSystem(8192);
            n.instanciateCommunication(new Socket(InetAddress.getLocalHost(), 4096));

            while (n.getCommunications().get(0).getReceiveManager().getReadObjects().isEmpty()) {
                // this line is unexpectedly magic
                System.out.println("Waiting for an object...");
            }

            System.out.println(n.getCommunications().get(0).getReceiveManager().getReadObjects().get(0));
            n.getCommunications().get(0).getSendManager().send(new String("No, I am not! We will talk later..."));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

/**
 * This class handles every incoming messages.
 */
public class ReceiveManager implements Runnable {

    private ObjectInputStream inputStream;
    private CommunicationManager communicationManager;
    private List readObjects;
    private boolean receive;

    public ReceiveManager(CommunicationManager communicationManager) throws IOException {
        this.communicationManager = communicationManager;
        this.inputStream = new ObjectInputStream(this.communicationManager.getSocket().getInputStream());
        this.readObjects = new ArrayList();
        this.receive = true;
    }

    @Override
    public void run() {
        Object object = null;

        try {
            while ((object = this.inputStream.readObject()) != null && this.hasToReceive()) {
                this.readObjects.add(object);
            }
        } catch (ClassNotFoundException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            this.setContinueToReceive(false);
        }
    }

    private boolean hasToReceive() {
        return this.receive;
    }

    public void setContinueToReceive(boolean value) {
        this.receive = value;
    }
}

/**
 * This class allows the user to send messages
 */
public class SendManager {

    private ObjectOutputStream outputStream;
    private CommunicationManager communicationManager;

    public SendManager(CommunicationManager communicationManager) throws IOException {
        this.communicationManager = communicationManager;
        this.outputStream = new ObjectOutputStream(this.communicationManager.getSocket().getOutputStream());
    }

    public void send(Object object) throws IOException {
        this.outputStream.writeObject(object);
        this.outputStream.flush();
    }
}

So basically, as you may have noticed in the ServerLauncher and the ClientLauncher, there are two "magic" instructions. 因此,基本上,就像您在ServerLauncher和ClientLauncher中注意到的那样,有两个“魔术”指令。 When those two lines are commented and I run the server then the client, nothing happens. 当对这两行进行注释并且我运行服务器然后运行客户端时,什么也没有发生。 The server and the client are simply running and never stop. 服务器和客户端只是在运行,永远不会停止。 However, when I uncomment these two magic lines, every works like a charm: messages are properly sent and received. 但是,当我取消对这两条魔术线的注释时,每条线都像一个符咒:正确发送和接收消息。

Would you guys know the reason of this unexpected behaviour ? 你们知道这种意外行为的原因吗?

Oh yeah, I forgot, if you guys want me to upload everything to test the project or whatever, just tell me :-) 哦,是的,我忘了,如果你们要我上载所有内容以测试项目或进行其他操作,请告诉我:-)

You're starving the CPU with those spin loops. 这些旋转循环使CPU处于饥饿状态。 You should sleep or wait while the queues are empty, or better still just take() from blocking queues. 您应该在队列为空时睡眠或等待,或者最好还是从阻塞队列中take()

NB Your loop condition isn't correct: 注意:您的循环条件不正确:

  1. readObject() doesn't return null at end of stream. readObject()在流的末尾不返回null It throws EOFException . 它抛出EOFException
  2. You should also test hasToReceive() before calling readObject() rather than afterwards. 您还应该调用readObject() 之前而不是之后测试hasToReceive() Otherwise you always do an extra read. 否则,您总是要多读一遍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM