在java中处理套接字
我正在用java为服务器创建一个套接字,在连接套接字之后,它会创建一个新线程,该线程可以访问套接字输入和输出流,然后当输入行进入时,该线程会阻塞并处理它们 我知道当输入流结束时,BufferedReader上的在java中处理套接字,java,multithreading,sockets,thread-safety,synchronized,Java,Multithreading,Sockets,Thread Safety,Synchronized,我正在用java为服务器创建一个套接字,在连接套接字之后,它会创建一个新线程,该线程可以访问套接字输入和输出流,然后当输入行进入时,该线程会阻塞并处理它们 我知道当输入流结束时,BufferedReader上的readln方法将返回null。这并不一定意味着套接字是关闭的,是吗?这是什么意思?因此,我想在套接字上运行close方法来很好地关闭它 我还了解,readln方法可以引发IOException,如果套接字当前处于阻塞状态,则在调用close方法后会引发IOException。还有什么时候
readln
方法将返回null。这并不一定意味着套接字是关闭的,是吗?这是什么意思?因此,我想在套接字上运行close
方法来很好地关闭它
我还了解,readln
方法可以引发IOException,如果套接字当前处于阻塞状态,则在调用close
方法后会引发IOException。还有什么时候可以抛出这个?套接字在抛出后是否仍然打开,或者是否始终关闭并准备进行垃圾收集等
这是我目前拥有的代码,我真的不知道如何正确处理断开连接。目前,我认为如果在套接字等待线路时调用disconnect
方法,这可能会导致死锁,因为disconnect
将在套接字上调用close
。这将在readLine
上抛出IOException
,这将导致catch块再次调用disconnect
public class SocketManager {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private String ip;
private int port;
private Object socketLock = new Object();
public SocketManager(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connect() throws UnableToConnectException, AlreadyConnectedException {
synchronized(socketLock) {
if (socket == null || socket.isClosed()) {
throw (new AlreadyConnectedException());
}
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw (new UnableToConnectException());
}
new Thread(new SocketThread()).start();
}
}
public void disconnect() throws NotConnectedException {
synchronized(socketLock) {
if (isConnected()) {
throw (new NotConnectedException());
}
try {
socket.close();
} catch (IOException e) {}
}
}
public boolean isConnected() {
synchronized(socketLock) {
return (socket != null && !socket.isClosed());
}
}
private class SocketThread implements Runnable {
@Override
public void run() {
String inputLine = null;
try {
while((inputLine = in.readLine()) != null) {
// do stuff
}
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e) {}
}
} catch (IOException e) {
// try and disconnect (if not already disconnected) and end thread
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e1) {}
}
}
}
}
}
我主要想知道实现以下目标的最佳方法:
- 编写一个连接到套接字并启动一个单独线程侦听输入的连接方法
- 编写一个disconnect方法,该方法断开与套接字的连接,并终止正在侦听输入的线程
- 处理与远程套接字的连接中断的情况
谢谢 为了确保与套接字关联的所有资源都被释放,您必须在完成与该套接字的工作时调用close()方法。 典型的IO异常处理模式是,您捕获它,然后调用close()方法尽最大努力清理所有内容
因此,您必须做的唯一一件事是确保在每个套接字的生命周期内调用close()。您走上了正确的道路。我不会使用“readline”,只使用原始阅读和“do stuff” 应限于构造接收数据的队列。同样,书面答复 应该是一个单独的线程,用于清空要发送的数据队列
尽管socket保证了完整性,但内容还是会出错,有时您会收到毫无意义的数据。在“读”和“写”下面有大量的东西,没有一个系统是完美的或没有bug的。在您的读写级别添加您自己的带有校验和的包装器,这样您就可以确保您收到了预期要发送的内容。当我说它可能会导致死锁时,我想我错了 将会发生的是:
in.readLine()
阻塞- 关机输入()
- 关机输出()
shutdownInput()
将结束EOF符号发送到输入流中,意思是.readline()中的in
返回null,循环干净地退出shutdownOutput()
发送TCP终止序列,通知服务器正在断开连接
在socket.close()之前调用这两个函数更有意义,因为这意味着线程将很好地退出,而不是因为抛出异常而退出,这会带来更大的开销
这是修改后的代码:
public class SocketManager {
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader in = null;
private String ip;
private int port;
private Object socketLock = new Object();
public SocketManager(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void connect() throws UnableToConnectException, AlreadyConnectedException {
synchronized(socketLock) {
if (socket == null || socket.isClosed()) {
throw (new AlreadyConnectedException());
}
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw (new UnableToConnectException());
}
new Thread(new SocketThread()).start();
}
}
public void disconnect() throws NotConnectedException {
synchronized(socketLock) {
if (isConnected()) {
throw (new NotConnectedException());
}
try {
socket.shutdownInput();
} catch (IOException e) {}
try {
socket.shutdownOutput();
} catch (IOException e) {}
try {
socket.close();
} catch (IOException e) {}
}
}
public boolean isConnected() {
synchronized(socketLock) {
return (socket != null && !socket.isClosed());
}
}
private class SocketThread implements Runnable {
@Override
public void run() {
String inputLine = null;
try {
while((inputLine = in.readLine()) != null) {
// do stuff (probably in another thread)
}
// it will get here if socket.shutdownInput() has been called (in disconnect)
// or possibly when the server disconnects the clients
// if it is here as a result of socket.shutdownInput() in disconnect()
// then isConnected() will block until disconnect() finishes.
// then isConnected() will return false and the thread will terminate.
// if it ended up here because the server disconnected the client then
// isConnected() won't block and return true meaning that disconnect()
// will be called and the socket will be completely closed
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e) {}
}
} catch (IOException e) {
// try and disconnect (if not already disconnected) and end thread
if (isConnected()) {
try {
disconnect();
} catch (NotConnectedException e1) {}
}
}
}
}
}