当使用ServerSockets和Sockets时,BufferedReader挂起,并且似乎无法正确建立连接

J_mie6

编辑:我已通过在服务器代码中添加一行来更正代码中的以下错误

我正在尝试编写一些套接字代码,以允许我将数据从一台计算机发送到另一台计算机以进行游戏(为简单起见,我们可以将其视为井字游戏,不需要发送太多数据,只是几个数字)。为了实现这一点,我编写了两个类,ServerClient目前,我正在使用端口1234通过localhost进行测试,而我仅使用该程序的一个实例(尽管在尝试使用两个实例时会出现相同的问题)。

首先是下面的代码,然后我可以更深入地了解该问题,以及我为尝试找出问题所在而进行的测试:

public class Server
{
    private ServerSocket server;
    private Socket socket;

    private Client socketHandler;

    private static final int DEFAULT_PORT = 1234;

    public Server() { this(DEFAULT_PORT); }
    public Server(int port)
    {
        Thread thread = new Thread()
        {
            public void run()
            {
                try
                {
                    System.out.println("Attempting to Establish Connection");
                    server = new ServerSocket(port);
                    socket = server.accept();
                    socketHandler = new Client(port, socket); //THIS LINE ADDED
                    System.out.println("Server Online!");
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };

        thread.setDaemon(true);
        thread.start();
    }

    //ADJUSTED
    Client getSocketHandler()
    {
        return socketHandler;
    }

    public void kill()
    {
        try
        {
            if (socket != null) socket.close();
            if (server != null) server.close();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            socket = null;
            server = null;
        }
    }
}

public class Client
{
    public static final int DEFAULT_PORT = 1234;
    public static final String DEFAULT_HOST = "localhost";
    private static final String THUMP_THUMP = "thump thump";
    private static final int PULSE = 1000;

    private int port;
    private String ip;

    private Socket socket;
    private BufferedReader input = null;
    private PrintWriter output = null;

    boolean closed = true;

    String data = "";

    public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
    public Client(int port) { this(port, DEFAULT_HOST, null); }
    public Client(int port, String ip) { this(port, ip, null); }
    public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
    public Client(String ip) { this(DEFAULT_PORT, ip, null); }
    public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
    public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
    public Client(int port, String ip, Socket server)
    {
        socket = server;
        this.ip = ip;
        this.port = port;

        Thread thread = new Thread()
        {
            public void run()
            {                
                try
                {
                    initialise(server);
                    String line;
                    startHeartbeat();
                    while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
                    System.out.println("We are about to listen!");
                    while (!isClosed())
                    {
                        System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
                        line = input.readLine(); //offending line
                        System.out.println("post-read"); //this line was used to determine when the block was lifted
                        if (line != null)// || line != THUMP_THUMP)
                        {
                            System.out.println(line);
                            data += line + "\n";
                        }
                    }
                    System.out.println(data);
                    kill();
                    System.out.println("Connection Closed!");
                }
                catch (SocketException e)
                {
                    e.printStackTrace();
                    System.out.println("Server closed!");
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };

        thread.setDaemon(true);
        thread.start();
    }

    private void initialise(Socket server)
    {
        try
        {
            if (server == null) socket = new Socket(ip, port);
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
        }
        catch (IOException e) { e.printStackTrace(); }
    }

    public boolean post(String text)
    {
        synchronized(this)
        {
            output.println(text);
            output.flush();
            return !output.checkError();
        }
    }

    public void kill()
    {
        try
        {
            if (input != null) input.close();
            if (socket != null) socket.close();
        }
        catch(IOException e) { e.printStackTrace(); }
        finally
        {
            input = null;
            socket = null;
        }
    }

    public void killOutputStream()
    {
        try
        {
            if (output != null) output.close();
        }
        catch (Exception e) { e.printStackTrace(); }
        finally
        {
            output = null;
        }
    }

    //////////////////////////////////
    ///////// Socket Control /////////
    //////////////////////////////////

    synchronized boolean isClosed()
    {
        return closed;
    }

    synchronized void setClosed(boolean b)
    {
        closed = b;
    }

    //We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
    void startHeartbeat()
    {
        Thread heartbeat = new Thread()
        {
            public void run()
            {
                while (output != null)
                {
                    setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
                    synchronized(this)
                    {
                        try
                        {
                            this.wait(PULSE);
                        }
                        catch (InterruptedException e) {}
                    }
                }
                setClosed(true);
            }
        };
        heartbeat.setDaemon(true);
        heartbeat.start();
    }
}

问题

当客户端启动后(创建服务器之后),它无法读取通过(甚至是心跳)发送的任何数据,实际上该代码不会line = input.readLine()在读取线程中经过(从现在开始,这称为违规行) ,直到服务器断开连接为止(见下文)。

这是常规测试的顺序:

Server()被调用并将结果Server存储在serverConnection变量中,然后Client(serverConnection != null ? serverConnection.getSocket() : null)被调用并将新Client存储在中clientConnection

因为我们可以使用心跳测试它是否正常工作,所以不需要发送其他数据,并且可以通过调用服务器serverConnection.kill()clientConnection.killOutputStream()在等待一段时间后终止服务器

结果如下:

Attempting to Establish Connection Server Online! 
We are about to listen!

Connection Closed!

其中,空行表示在连接过程中接收到的非空数据,即没有任何数据。

我期望这样:

Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!

我花了一些时间通过注释掉或以相同的测试格式略微更改代码来执行不同的测试(特殊情况除外,该特殊情况为6),并得出以下结论:

观察结果

  1. 仅当套接字关闭且输出流关闭时,程序才会越过有问题的行。
  2. 当该readline()方法开始处理时(在心跳中断之前不久),它在流中什么也没有检测到,甚至没有检测到THUMP_THUMP
  3. 当套接字关闭,但输出流未关闭时,该readline()方法开始处理,仅检测不到任何内容,心跳将其切断。没有SocketException,即使人们预期。
  4. 如果未关闭套接字,并且仅关闭了输出流,SocketException则会触发a,表明套接字已关闭。
  5. netstat -an在命令提示符下使用过,当服务器启动时,端口1234是LISTENING。当客户端连接时,它仍在侦听,表示没有连接。
  6. 我设置了一些python代码以通过端口1234连接到其自身,但是我在python代码中犯了一个错误,因此服务器没有关闭,但仍处于打开状态。因此,我决定将Java客户端连接到服务器,然后看看会发生什么。我通过运行Client(null)非主机的客户端代码来做到这一点结果导致端口读取已建立,并且python服务器正在回显“ thump thump”,而Java代码已成功读取它。没有挂,它工作完美。

这使我相信问题出在服务器代码上,因为python服务器能够与Java客户端成功通信,但是Java客户端无法与Java服务器通信。

在执行此测试之前,我一直专注于客户端代码,认为是错误的。我在这里发现的所有具有类似症状的问题(请参见此处此处此处以及其他内容)对我来说都是空白,已经写了解决方案(大多数是由于输出流未刷新或被省略),我没有失败,或者解决方案不能解决我的问题,因此在这种情况下被移除以支持心跳)。我原本基于我的代码关闭的这个文章。

在尝试解决此问题4天后,我无所适从。。。我在这里想念的是什么?为什么服务器代码无法按我预期的方式工作?如果有人需要进一步澄清我的代码,请询问!

作为注释,测试代码通过用javafx编写的简单的简约GUI(尽管不是fxml)运行,无论这是否是一个问题,我确定,因为它可以与Python一起使用,所以我认为不会服务器。这段代码是用Java 8编译的

JavaCoder16

考虑到服务器端没有对输入/输出的处理,我对您为什么认为它比input.readLine()会更困惑感到有些困惑。

客户/服务器的连接就像打网球一样,因为一面发球,另一面必须先接球,然后发回球(可能带有不同的信息)。您的服务器端必须处理从启动心跳方法接收到的输入,然后将响应发送回给您。input.readLine()函数将阻塞线程,直到它从另一端接收到数据为止,因此,是的,代码在此处停止,并等待服务器将“网球”发回。在服务器类中,您应该添加输入和输出流,以处理心跳输入并将一串数据发送回客户端。

服务器:

OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";

while(true){
    is.read();
    os.write(response.getBytes());
    os.flush();
}

在此示例中,客户端应保持不变,只需将上述代码添加到您的服务器即可。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

强制断开连接时,BufferedReader.readLine()挂起

来自分类Dev

强制断开连接时,BufferedReader.readLine()挂起

来自分类Dev

使用Paypal API时无法建立SOAP连接

来自分类Dev

无法使用ESP8266和Arduino uno建立连接

来自分类Dev

无法使用mongodb和express与Docker建立连接

来自分类Dev

Firefox 无法建立连接 - websocket 和 heroku

来自分类Dev

无法使用aSmack 4.0.2建立新连接

来自分类Dev

无法使用类加载器建立连接

来自分类Dev

我无法使用Java建立与Mariadb的连接?

来自分类Dev

似乎无法正确使用PHP命名空间

来自分类Dev

使用证书访问.NET Framework中的Web服务时无法建立信任连接

来自分类Dev

在Laravel 5.2中使用socket.io建立连接时io.on无法正常工作

来自分类Dev

在Laravel 5.2中使用socket.io建立连接时io.on无法正常工作

来自分类Dev

当我使用CORS时,AngularJS $ http似乎无法正确响应

来自分类Dev

无法建立JDBC连接

来自分类Dev

如何正确使用BufferedReader

来自分类Dev

我无法正确比较使用bufferedReader从文件读取的单词

来自分类Dev

仅在首次尝试时无法建立SSL连接

来自分类Dev

我是Java的新手,并且要交作业,我似乎无法获得平均正确的方法

来自分类Dev

连接到套接字时似乎无法正常工作

来自分类Dev

选择查询不显示任何结果并且似乎挂起

来自分类Dev

三个Web应用程序使用相同的数据库时,无法建立数据库连接

来自分类Dev

连接到ProFTPD时出现FileZilla错误:“无法建立数据连接:ETIMEDOUT-连接尝试超时”

来自分类Dev

线程似乎无法干净退出-线程挂起

来自分类Dev

获取某些视频时 requestAVAssetForVideo 似乎挂起

来自分类Dev

Nutch无法使用Mongodb在Elasticsearch上正确建立索引

来自分类Dev

为什么我无法使用python建立与RabbitMQ的连接?

来自分类Dev

无法使用LoadRunner建立从CLIENT到PROXY的SSL连接

来自分类Dev

无法使用PHP 5.6.3与Composer建立SSL连接

Related 相关文章

  1. 1

    强制断开连接时,BufferedReader.readLine()挂起

  2. 2

    强制断开连接时,BufferedReader.readLine()挂起

  3. 3

    使用Paypal API时无法建立SOAP连接

  4. 4

    无法使用ESP8266和Arduino uno建立连接

  5. 5

    无法使用mongodb和express与Docker建立连接

  6. 6

    Firefox 无法建立连接 - websocket 和 heroku

  7. 7

    无法使用aSmack 4.0.2建立新连接

  8. 8

    无法使用类加载器建立连接

  9. 9

    我无法使用Java建立与Mariadb的连接?

  10. 10

    似乎无法正确使用PHP命名空间

  11. 11

    使用证书访问.NET Framework中的Web服务时无法建立信任连接

  12. 12

    在Laravel 5.2中使用socket.io建立连接时io.on无法正常工作

  13. 13

    在Laravel 5.2中使用socket.io建立连接时io.on无法正常工作

  14. 14

    当我使用CORS时,AngularJS $ http似乎无法正确响应

  15. 15

    无法建立JDBC连接

  16. 16

    如何正确使用BufferedReader

  17. 17

    我无法正确比较使用bufferedReader从文件读取的单词

  18. 18

    仅在首次尝试时无法建立SSL连接

  19. 19

    我是Java的新手,并且要交作业,我似乎无法获得平均正确的方法

  20. 20

    连接到套接字时似乎无法正常工作

  21. 21

    选择查询不显示任何结果并且似乎挂起

  22. 22

    三个Web应用程序使用相同的数据库时,无法建立数据库连接

  23. 23

    连接到ProFTPD时出现FileZilla错误:“无法建立数据连接:ETIMEDOUT-连接尝试超时”

  24. 24

    线程似乎无法干净退出-线程挂起

  25. 25

    获取某些视频时 requestAVAssetForVideo 似乎挂起

  26. 26

    Nutch无法使用Mongodb在Elasticsearch上正确建立索引

  27. 27

    为什么我无法使用python建立与RabbitMQ的连接?

  28. 28

    无法使用LoadRunner建立从CLIENT到PROXY的SSL连接

  29. 29

    无法使用PHP 5.6.3与Composer建立SSL连接

热门标签

归档