挂有两个侦听器的Java套接字应用程序

时间:2018-06-19 15:12:58

标签: java sockets client-server objectinputstream objectoutputstream

我正在本地计算机上运行客户端和服务器,并试图在两者之间发送文本消息。双方都可以读写。我使用ObjectInputStreamObjectOutputStream是因为我需要序列化对象。 Github repo

我的问题是,当我尝试从双方发送消息时,它们无法传递到另一端,并且听众挂起。

Host.java

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Host {
    private ServerSocket serverSocket;
    private Socket clientSocket;
    private ObjectOutputStream out;
    private ObjectInputStream in;
    private int portNumber = Settings.PORT;

    public Host() {
        acceptConnection();
        CommandListener commandListener = new CommandListener(in);
    }

    private void acceptConnection() {
        try {
            serverSocket = new ServerSocket(portNumber);
            clientSocket = serverSocket.accept();
            out = new ObjectOutputStream(clientSocket.getOutputStream());
            in = new ObjectInputStream(clientSocket.getInputStream());
        } catch (IOException e) {
            System.out.println("Exception caught when trying to listen on port "
                    + portNumber + " or listening for a connection");
            System.out.println(e.getMessage());
        }
    }

    public ObjectOutputStream getOut() {
        return out;
    }

    public ObjectInputStream getIn() {
        return in;
    }
}

Client.java

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
    private int portNumber = Settings.PORT;
    private ObjectOutputStream out;
    private ObjectInputStream in;
    private Socket clientSocket;

    public Client(String ip) {
        connectToHost(ip);
        CommandListener commandListener = new CommandListener(in);
    }

    public ObjectOutputStream getOut() {
        return out;
    }

    public ObjectInputStream getIn() {
        return in;
    }

    private void connectToHost(String ip) {
        try {
            clientSocket = new Socket(ip, portNumber);
            out = new ObjectOutputStream(clientSocket.getOutputStream());
            in = new ObjectInputStream(clientSocket.getInputStream());

        } catch (UnknownHostException e) {
            System.err.println("Don't know about host " + ip);
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to " + ip);
            e.printStackTrace();
        }
    }
}

CommandListener.java类是一个由客户端和服务器独立启动的线程。

import java.io.IOException;
import java.io.ObjectInputStream;

public class CommandListener implements Runnable{
    private ObjectInputStream in;

    public CommandListener(ObjectInputStream in) {
        this.in = in;
        run();
    }

    public void run() {
        String inboundCmd;
        try {
            System.out.println("listener running, waiting for inbound command");
            inboundCmd = (String) in.readObject();
            System.out.println("listener read inbound command" + inboundCmd);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

打印出listener running, waiting for inbound command后,两者均挂起。 这是我启动客户端和服务器的方法:

RunHost.java

import java.io.IOException;
import java.io.ObjectOutputStream;

public class RunHost {
    public static void main(String[] args) throws IOException {
        Host host = new Host();
        ObjectOutputStream out = host.getOut();
        out.writeObject("host sending");
        out.flush();
    }
}

RunClient.java

import java.io.IOException;
import java.io.ObjectOutputStream;

public class RunClient {
    public static void main(String[] args) throws IOException {
        Client client = new Client("localhost");
        ObjectOutputStream out = client.getOut();
        out.writeObject("client sending");
        out.flush();
    }
}

有什么解决方法吗?

1 个答案:

答案 0 :(得分:1)

主机和客户端似乎都“挂起”的原因仅仅是因为没有人在听另一方之前就设法写了任何东西。

您应该在RunHost.java之前运行RunClient.java。从那里开始,您可以跟踪程序:

  1. 构造一个新主机(即RunHost.java已运行)
  2. 阻塞并等待客户端套接字连接
  3. 构建新客户端(即RunClient.java已运行)
  4. ServerSocketClientSocket的输入和输出流均已初始化
  5. ServerSocketClientSocket都开始构建CommandListener
  6. ServerSocketClientSocket都开始监听输入

看到问题了吗?主要问题是因为您在run()构造函数中调用了方法CommandListener,所以服务器端和客户端都开始阻塞监听,而没有任何人发送任何东西。

一种快速解决方案是从run()构造函数中取出CommandListener调用,然后在准备好它时分别调用它。

例如:

CommandListener.java中的构造函数更改为:

public CommandListener(ObjectInputStream in) {
    this.in = in;
}

添加一种在CommandListener中为客户端获取Client.java的方法(请注意,这意味着您应通过在{{1}中执行CommandListener来存储cl = new CommandListener(in); }构造函数):

Client

public CommandListener getCL() { return cl; } 更改为以下内容:

RunClient.java

最后,在public static void main(String[] args) throws IOException { Client client = new Client("localhost"); ObjectOutputStream out = client.getOut(); out.writeObject("client sending"); out.flush(); CommandListener cl = client.getCL(); cl.run(); } 的构造函数中调用CommandListener的{​​{1}}方法:

run()

它应该按预期工作。

但是,老实说,考虑到Host造成的混乱,您可能首先要重新考虑使用该类。我的意思是,在这里似乎没有必要,所以...

P / S随时让我知道是否有任何不清楚的地方/仍然无法解决问题