编辑:我已通过在服务器代码中添加一行来更正代码中的以下错误
我正在尝试编写一些套接字代码,以允许我将数据从一台计算机发送到另一台计算机以进行游戏(为简单起见,我们可以将其视为井字游戏,不需要发送太多数据,只是几个数字)。为了实现这一点,我编写了两个类,Server
和Client
。目前,我正在使用端口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
则会触发a,表明套接字已关闭。netstat -an
在命令提示符下使用过,当服务器启动时,端口1234是LISTENING。当客户端连接时,它仍在侦听,表示没有连接。Client(null)
非主机的客户端代码来做到这一点。结果导致端口读取已建立,并且python服务器正在回显“ thump thump”,而Java代码已成功读取它。没有挂,它工作完美。这使我相信问题出在服务器代码上,因为python服务器能够与Java客户端成功通信,但是Java客户端无法与Java服务器通信。
在执行此测试之前,我一直专注于客户端代码,认为它是错误的。我在这里发现的所有具有类似症状的问题(请参见此处,此处和此处以及其他内容)对我来说都是空白,已经写了解决方案(大多数是由于输出流未刷新或被省略),我没有失败,或者解决方案不能解决我的问题,因此在这种情况下被移除以支持心跳)。我原本基于我的代码关闭的这个文章。
在尝试解决此问题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();
}
在此示例中,客户端应保持不变,只需将上述代码添加到您的服务器即可。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句