我有一个处理套接字连接的线程:
BufferedReader socketInput = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
while (true)
{
String line = socketInput.readLine();
// do stuff
}
正如我在本网站上的几个答案中所读到的,推荐的解决方案是使用一个标志,一个线程设置并且我的(套接字处理)线程在该标志改变状态时检查并终止自身。类似的东西:
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
但是当readLine()
仍在等待输入时,这可能会卡住。我想我可以设置超时:
mySocket.setSoTimeout(100);
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
哪个可能会有效但我仍然会在我的线程之前得到100毫秒的延迟"意识到"国旗的状态发生了变化。
线程有没有办法实现"它应该结束吗?如果没有,我的解决方案(超时和标志done
)是否正确?
修改:我已澄清socketInput
类型为BufferedReader
(或者我考虑Scanner
)。
答案 0 :(得分:3)
处理此问题的最常用方法是从另一个Thread关闭套接字。这将导致读取端解除阻塞并退出套接字关闭的(预期)错误。根据您可用的套接字API,也可能仅关闭读取端。简而言之,JDK shutdownInput()
可能会起作用。
如果您希望稍后继续从套接字读取这些obvisouly将无法正常工作。你的解决方案应该在那里工作,但是因为你基本上在100毫秒内轮询套接字,所以性能和反应性显然更糟。
答案 1 :(得分:2)
解决方案是正确的,当完成设置为true时它将退出。 是的,readLine将始终等待100ms,如果你不想等待,你可以通过调用thread.interrupt()来中断线程,但它不是很干净的方式。
答案 2 :(得分:2)
SelectionKey.OP_READ
socket.getChannel()
non-blocking和register it配置到选择器
select()
方法,该方法会在有一些数据需要阅读时返回,以便您拨打readLine()
(即select()
返回> 0
)每当您想要结束套接字处理时,请设置done
标志并调用您的选择器wakeup()
方法。这将使select()
立即返回(可能为0,如果有活动则为1)。然后,您可以检查done
标志并正常结束线程。
这是一个快速实施。请注意,我将BufferedReader
作为参数传递,就像您在线程中打开它一样,您也应该将其关闭,这也会关闭套接字,因此必须在外部完成。有两种方法可以通知线程正常停止处理输入,另一种方法是发送数据:
public class SocketHandler extends Thread {
private Socket sok;
private BufferedReader socketInput;
private Selector sel;
private SocketChannel chan;
private boolean done;
public SocketHandler(Socket sok, BufferedReader socketInput) throws IOException {
this.sok = sok;
chan = sok.getChannel();
chan.configureBlocking(false);
sel = Selector.open();
chan.register(sel, SelectionKey.OP_READ);
this.socketInput = socketInput;
done = false;
}
@Override
public void run() {
while (!done) {
try {
if (sel.select() == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
// Only one channel is registered on only one operation so we know exactly what happened.
sel.selectedKeys().clear();
doRead();
// Otherwise: loop through sel.selectedKeys(), check for readability and clear the set
}
try {
sel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void doRead() {
try {
String line = socketInput.readLine();
// TODO: process 'line'
} catch (IOException e) {
e.printStackTrace();
}
}
public void signalStop() {
done = true;
if (sel != null)
sel.wakeup(); // Get out of sel.select()
}
public void doWrite(byte[] buffer) throws IOException { // Or "String message"
sok.getOutputStream().write(buffer); // Or anything else
}
}
答案 3 :(得分:0)
了解何时完成套接字连接的最佳方法是尝试读取内容。如果read方法返回-1,则可以结束线程套接字连接
byte[] data = new byte[2048];
while (!done) {
int count = input.read(data);
if (count <= 0) {
if (count < 0)
done = true;
continue;
}
String request = new String(data, 0, count);
//do stuff
}
如果count == -1,我们尝试读取输入中的内容,套接字客户端现在断开连接,现在我们可以通过更改done的值来结束循环。