2 a1003865572 a1003865572 于 2015.06.14 22:12 提问

关于WebSocket的问题 为什么浏览器关闭后会出一下异常

错误信息
```java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.net.SocketInputStream.read(SocketInputStream.java:90)
at test.UserSocket.run(UserSocket.java:43)
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.net.SocketInputStream.read(SocketInputStream.java:90)
at test.UserSocket.run(UserSocket.java:43)

这是一个WebScoket 的小测试。我开了3个浏览器测试正常后,关闭其中一个就会这个异常以下是我的代码麻烦各位大神给看看


package test;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import sun.applet.Main;

public class ServerSocketTest {
public static List clientSocket = new ArrayList();

public ServerSocketTest() throws IOException{
    ServerSocket ss = new ServerSocket(30000);
    System.out.println("服务器启动等待客户端连接");
    while(true){
        Socket s =ss.accept();//等待客户端连接
        clientSocket.add(s);
        System.out.println("客户端总人数"+clientSocket.size());
        //为新用户启动线程
        new UserSocket(s).start();
    }
}
public static void main(String[] args) throws IOException {
    new ServerSocketTest();
}

}

下面是线程代码



package test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.security.MessageDigest;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import sun.misc.BASE64Encoder;

public class UserSocket extends Thread{
private Socket socket;

public UserSocket(Socket socke){
    this.socket = socke;
}
@Override
public void run() {
    try {
        InputStream is = socket.getInputStream();//获取用户输入流
        OutputStream ops = socket.getOutputStream();//获取用户输出流
        byte[] buff = new byte[1024];//字节
        String red = ""; //用了存放客户端请求过来的内容(客户端信息)
        // 读取数据,此时建立与wabSocket的握手
        int count = is.read(buff);//读取客户端请求内容的长度
        if(count > 0){
            //客户端请求数据转化字符串
            red = new String(buff,0,count);
            //获取WebSocket的值
            String seckey = getSecWebSocketKey(red);
            String response = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: "
                + "websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "
                + getSecWebSocketAccept(seckey) + "\r\n\r\n";
            //推送向客户端
            ops.write(response.getBytes("utf-8"));
        int hasRedad = 0;
        // 不断读取WebSocket发送过来的数据
        System.out.println("while循环前,等待前端推送数据。。。。。。。。。。。。");
        while((hasRedad = is.read(buff))>0){//判断循环读取
            System.out.println("后台接收到值,进入While循环处理");
            /*
             * 因为WebSocket发送过来的数据遁寻了一定的协议格式, 其中第3~6个字节是数据掩码,
             * 从第七个字节开始才是真正的有效数据。 因此程序使用第3~6个字节对后面的数据进行了处理
             */
            for (int i = 0; i < hasRedad - 6; i++) {
                buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]);
            }
            //获得从浏览器发送过来的数据
            String pushMsg = new String(buff,6,hasRedad - 6, "utf-8");//第一个值要读取的字节,从第几个开始读取,字符串的总长度,字符集
            //便利Socket集合,向每个Socket对象发送信息
            for (Iterator<Socket> it = ServerSocketTest.clientSocket.iterator();it.hasNext(); ) {
                try {
                    Socket s = it.next();
                    byte[] pushHead = new byte[2];
                    pushHead[0] = buff[0];
                    pushHead[1] = (byte) pushMsg.getBytes("utf-8").length;
                    //发送前两个字节
                    s.getOutputStream().write(pushHead);
                    //发送有效数据
                    s.getOutputStream().write(pushMsg.getBytes("utf-8"));

                } catch (SocketException e) {
                    //如果捕获到异常将其从集合中删除
                    // 如果捕捉到异常,表明该Socket已经关闭
                    it.remove();
                }
            }

        }





        }

    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

// 获取WebSocket请求的Seckey
private String getSecWebSocketKey(String req) {
    // 构建正则表达式,获取Sec-WebSocket-Key:后面的内容
    Pattern p = Pattern.compile("^(Sec-WebSocket-Key:).+",
            Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    Matcher m = p.matcher(req);
    if (m.find()) {
        // 提取Sec-WebSocket-Key
        String foundstring = m.group();
        return foundstring.split(":")[1].trim();
    } else {
        return null;
    }
}

// 根据WebSocket请求的Seckey计算SecAccept
private String getSecWebSocketAccept(String key) throws Exception {
    String guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    key += guid;
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(key.getBytes("ISO-8859-1"), 0, key.length());
    byte[] shalHash = md.digest();
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(shalHash);
}

}

刚才又调试了几次,发现了一些新的东西。
同时开启多个页面进行程序测试。当其中一个页面关闭时,这个页面向后台发送了一条数据,后台接收后处理并发送给其他页面。但是这个页面关闭了,本线程下发送给其他页面的信息全部发送失败。由于发送信息发送不出去,本线程就在此处

} catch (SocketException e) {
                    //如果捕获到异常将其从集合中删除
                    // 如果捕捉到异常,表明该Socket已经关闭
                    it.remove();
                }
把其他的Socket对象全部删除了,导致所有的Socket对象连接都断开了。求教大神们有没有什么靠谱的解决办法

2个回答

bulusli3
bulusli3   Ds   Rxr 2015.06.16 12:25

关掉浏览器报错是正常的,因为有一个socket连接断开了,这个只要不影响其它地方,忽略即可。

Alonme
Alonme   2017.06.06 16:53

应该是这个在关闭浏览器前断开连接。
js里添加:window.onbeforeunload = function(){websocket.close(); }

Csdn user default icon
上传中...
上传图片
插入图片