原文:http://ivan4126.blog.163.com/blog/static/20949109220135284278806/
最近在开发中遇到一个问题,就是如何判断远端服务器是否已经断开连接,如果断开那么需要重新连接。
首先想到socket类的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,但经过试验并查看相关文档,这些方法都是本地端的状态,无法判断远端是否已经断开连接。
然后想到是否可以通过OutputStream发送一段测试数据,如果发送失败就表示远端已经断开连接,类似ping,但是这样会影响到正常的输出数据,远端无法把正常数据和测试数据分开。
最后又回到socket类,发现有一个方法sendUrgentData,查看文档后得知它会往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的,太好了,正是我需要的!
java socekt 同步套节字编程主要用到java.net.Socket类,通常情况下我们需要socket的长连接模式。其次就是在连接的另一端断开之后需要及时响应。
对于连接的判断,socket提供的isClosed,isConnected等都是判断本地套节字的状态。要判断运程的连接,可以通过发送紧急数据来判断,紧急数据发送成功与否,就表示远程是否断开。
- public class Nksocket extends Thread{
- public String ip=null;//连接服务器的IP
- public Integer port=null;//连接服务器的端口
- private Socket socket=null;//套节字对象
- private boolean close = false; // 关闭连接标志位,true表示关闭,false表示连接
- private Integer sotimeout=1*1*10;//超时时间,以毫秒为单位
- //------------------------------------------------------------------------------
- public Nksocket(){
- init();
- }
- public Nksocket(String ip,Integer port){
- setIp(ip);
- setPort(port);
- init();
- }
- /**
- * 初始化socket对象
- */
- public void init(){
- try {
- InetAddress address = InetAddress.getByName(getIp());
- socket = new Socket(address,getPort());
- socket.setKeepAlive(true);//开启保持活动状态的套接字
- socket.setSoTimeout(sotimeout);//设置超时时间
- close=!Send(socket,"2");//发送初始数据,发送成功则表示已经连接上,发送失败表示已经断开
- }catch(UnknownHostException e) {
- e.printStackTrace();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- /**
- * 读数据线程
- */
- public void run() {
- while(true){
- //---------读数据---------------------------
- close = isServerClose(socket);//判断是否断开
- if(!close){//没有断开,开始读数据
- String readtext = ReadText(socket);
- if(readtext!=null && readtext.trim().length()>0){
- System.out.println("读取数据:"+readtext);
- }
- }
- //---------创建连接-------------------------
- while(close){//已经断开,重新建立连接
- try{
- System.out.println("重新建立连接:"+getIp()+":"+getPort());
- InetAddress address = InetAddress.getByName(getIp());
- socket = new Socket(address,getPort());
- socket.setKeepAlive(true);
- socket.setSoTimeout(sotimeout);
- close = !Send(socket,"2");
- System.out.println("建立连接成功:"+getIp()+":"+getPort());
- }catch(Exception se){
- System.out.println("创建连接失败:"+getIp()+":"+getPort());
- close=true;
- }
- }
- }
- }
- /**
- * 发送数据,发送失败返回false,发送成功返回true
- * @param csocket
- * @param message
- * @return
- */
- public Boolean Send(Socket csocket,String message){
- try{
- PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
- out.println(message);
- return true;
- }catch(Exception se){
- se.printStackTrace();
- return false;
- }
- }
- /**
- * 读取数据,返回字符串类型
- * @param csocket
- * @return
- */
- public String ReadText(Socket csocket){
- try{
- csocket.setSoTimeout(sotimeout);
- InputStream input = csocket.getInputStream();
- BufferedReader in = new BufferedReader(new InputStreamReader(input));
- char[] sn = new char[1000];
- in.read(sn);
- String sc = new String(sn);
- return sc;
- }catch(IOException se){
- return null;
- }
- }
- /**
- * 判断是否断开连接,断开返回true,没有返回false
- * @param socket
- * @return
- */
- public Boolean isServerClose(Socket socket){
- try{
- socket.sendUrgentData(0);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
- return false;
- }catch(Exception se){
- return true;
- }
- }
- /**
- * 测试
- * @param ags
- */
- public static void main(String[] ags){
- Nksocket nksocket = new Nksocket("127.0.0.1",8089);
- nksocket.start();
- }
- //------------------------------------------------------------------------------
- public String getIp() {
- return ip;
- }
- public void setIp(String ip) {
- this.ip = ip;
- }
- public Integer getPort() {
- return port;
- }
- public void setPort(Integer port) {
- this.port = port;
- }
- }