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<Socket> clientSocket = new ArrayList<Socket>(); 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对象连接都断开了。求教大神们有没有什么靠谱的解决办法
反正我觉得浏览关闭肯定是会引用异常的,看每个浏览自己怎么处理了,和为服务器端,能做的就是多写几个try catch去处理它们。
但是他不能把其他的Socket也给删除掉啊 删除自己的就好了嘛,,这个代码改怎么控制呀 求帮助呀 大神
@倾听暮色下的雨声: 什么?你不是用了多线程了嘛,一个客户访问对应一个socket,一个socket对应一个线程,如果客户a把浏览器关了,就对应地把socketa关了呗,又不影响客户b的正常访问。
@angelshelter: 不行唉! 还是会报错的
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:44)
@倾听暮色下的雨声: 你看楼下的回复吧,it.remove();是很容易引起异常的,一般的,只要是迭带,就不能用remove.
@angelshelter:
@angelshelter: 去掉it.remove();方法后 我的代码是这样的
for ( it = ServerSocketTest.clientSocket.iterator();it.hasNext(); ) { try { Socket s = it.next().getSocket(); 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{ ServerSocketTest.clientSocket.remove(this.sok); try { this.sok.getSocket().close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
我只是截取了一部分, 但是这样写的话 ,程序还是会异常的 ,难道这个Scoket 就不能用this.sok.getSocket().close(); 方法么? 这个Socket 出异常了 就不能把它从集合中删除掉么? 我这样写有错么? 无脑了。。。。。
@倾听暮色下的雨声: 我的建议是,你试试看this.sok或this.sok.getSocket()的值是不是为空,如果不为空调用close还是报错的话,就不要调用close了。
还有,你这一次如果remove是写在finally,如果remove()还是被包含在for ( it = ServerSocketTest.clientSocket.iterator();it.hasNext(); )这个循环内的话,还是会报错的,反正就是这个循环内不能remove,要在循环外remove.
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();
}
}
你这段代码有问题,调用 it.remove() 后,还会继续使用迭代器,迭代器在遍历时不能修改。