gpt4 book ai didi

java - 使用ServerSockets和Sockets时,BufferedReader挂起,并且看来连接形式不正确

转载 作者:行者123 更新时间:2023-12-02 05:41:15 26 4
gpt4 key购买 nike

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

我正在尝试编写一些套接字代码,以允许我将数据从一台计算机发送到另一台计算机以进行游戏(为简单起见,我们可以将其视为井字游戏,不需要发送太多数据,几个数字)。为了实现这一点,我编写了两个类,分别为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),并观察到以下几点:

观察结果


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


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

在执行此测试之前,我一直专注于客户端代码,认为它是错误的。我在这里发现的所有具有类似症状的问题(请参见 hereherehere等)对我来说都是空白,它们已经写了解决方案(大部分是由于输出流未刷新,或省略了\ n(我没有失败,或者解决方案不能解决我的问题,因此在这种情况下已被删除以支持心跳)。我最初基于 this文章编写代码。

在尝试解决此问题4天后,我无所适从……我在这里想念什么?为什么服务器代码无法正常运行?如果有人需要进一步澄清我的代码,请询问!

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

最佳答案

考虑到服务器端没有对输入/输出的处理,我对您为什么认为它比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();
}


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

关于java - 使用ServerSockets和Sockets时,BufferedReader挂起,并且看来连接形式不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24497951/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com