今天遇到一个问题,就是推出了监听界面之后,再进来界面还能监听客户端连接服务端。
做法:
1.关闭界面的时候要把服务端线程停止。
2.先关闭跟客户端连接的socket
3.关闭服务端的socket.
4.关闭select选择器.
做完这些,以后再进这个界面就可以重新监听了。
这样可以修复下面这个问题了 W/System.err: at com.example.tcplibrary.tcpserver.TcpServer.a(Unknown Source)
W/System.err: at com.example.tcplibrary.tcpserver.TcpServer.run(Unknown Source)
有这个问题是因为端口资源被暂用了。
如果发现,服务端起来了,但是客户端连接不上,有可能是之前没清掉客户端跟服务端的连接。得清掉之后才能自动连接上。
下面是一个测试的小代码:
socket类的代码:
package gateway.demo.com.gatewaydemo.tcpserver; import android.util.Log; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; /** * Created by caifeng on 2018/7/11. */ public class TcpServer implements Runnable { private static final String TAG = "TcpServer"; private static TcpServer mTcpServer = null; private Selector mSelector; private SocketChannel mSocketChannel; private ServerSocketChannel server; private boolean work; public static TcpServer getInstance() { if (mTcpServer == null) { synchronized (TcpServer.class) { if (mTcpServer == null) { mTcpServer = new TcpServer(); } } } return mTcpServer; } private TcpServer() { } @Override public void run() { buildServerSocketChannel(); //建立服务端通道 iterationSelector(); //迭代选择器 } /** * 创建ServerSocketChannel * * @throws IOException */ private void buildServerSocketChannel() { try { mSelector = Selector.open(); } catch (IOException e) { e.printStackTrace(); } try { server = ServerSocketChannel.open(); } catch (IOException e) { e.printStackTrace(); } Log.d("TcpServer", "打开成功"); try { server.configureBlocking(false); } catch (IOException e) { e.printStackTrace(); } try { server.socket().bind(new InetSocketAddress(9190), 1024); } catch (IOException e) { e.printStackTrace(); } Log.d("TcpServer", "绑定成功"); try { server.register(mSelector, SelectionKey.OP_ACCEPT); } catch (ClosedChannelException e) { e.printStackTrace(); } Log.d("TcpServer", "注册成功"); } /** * 循环遍历SelectionKey */ private void iterationSelector() { while (work) { try { mSelector.select(1000); } catch (IOException e) { e.printStackTrace(); } SetselectionKeys = mSelector.selectedKeys(); Iterator iterator = selectionKeys.iterator(); SelectionKey selectionKey = null; while (iterator.hasNext()) { selectionKey = iterator.next(); iterator.remove(); if (selectionKey.isAcceptable()) { ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); try { mSocketChannel = serverSocketChannel.accept(); mSocketChannel.configureBlocking(false); mSocketChannel.register(mSelector, SelectionKey.OP_READ); Log.d(TAG, "连接成功"); } catch (IOException e) { e.printStackTrace(); selectionKey.cancel(); if (selectionKey.channel() != null) { try { selectionKey.channel().close(); } catch (IOException e1) { e1.printStackTrace(); } } } } if (selectionKey.isReadable()) { mSocketChannel = (SocketChannel) selectionKey.channel(); //获取t2时间 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); String content = ""; try { int readBytes = mSocketChannel.read(byteBuffer); // 写完就把状态关注去掉,否则会一直触发写事件(改变自身关注事件) selectionKey.interestOps(SelectionKey.OP_READ); } catch (IOException i) { //如果捕获到该SelectionKey对应的Channel时出现了异常,即表明该Channel对于的Client出现了问题 //所以从Selector中取消该SelectionKey的注册 selectionKey.cancel(); if (selectionKey.channel() != null) { try { selectionKey.channel().close(); } catch (IOException e) { e.printStackTrace(); } } } } } } closeSocket(); } private void closeSocket() { if (server != null) { try { server.socket().close(); Log.d(TAG, "关闭成功1"); } catch (IOException e) { e.printStackTrace(); } } try { if (mSocketChannel != null) { mSocketChannel.close(); Log.d(TAG, "关闭成功2"); } } catch (IOException e) { e.printStackTrace(); } try { if (mSelector != null) { mSelector.close(); Log.d(TAG, "关闭成功3"); } } catch (IOException e) { e.printStackTrace(); } } public boolean isWork() { return work; } public void setWork(boolean work) { this.work = work; } }
Activity的代码:
package gateway.demo.com.gatewaydemo.activity; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import gateway.demo.com.gatewaydemo.R; import gateway.demo.com.gatewaydemo.tcpserver.TcpServer; public class MainActivity extends AppCompatActivity { private TcpServer mTcpServer = TcpServer.getInstance(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTcpServer.setWork(true); new Thread(mTcpServer).start(); } @Override protected void onDestroy() { mTcpServer.setWork(false); super.onDestroy(); } }
我是推出activity停止的线程,具体需求你们可以自己设计。
希望能帮助有这个问题的人。