java socket 无故当机

    这是一个socket长连接的程序,代码如下。我是在windows命令窗口运行socket服务器的。如果有机器设备通过我规定好的代码请求服务器,我就给设备建立长连接进行通讯。然后如果有另外的客户端通过规定好的代码请求,我就发送指令给指定设备,然后设备返回信息,再返回给客户端,这种是短连接。但是很奇怪的就是,总有应该是网络的爬虫请求我的程序,总收到一些乱七八糟的字符串,但是因为这些字符串和我规定的不一样,所以是拦截在外面的,建立不了长连接。最麻烦的来了,当程序运行久了以后或者一定时间,我客户端请求服务器短连接就超时了,服务器命令窗口没显示信息,但是如果我ctrl+c结束一下,请求的字符串又能打印出来了了,好像整个程序挂起来没反应,以至于程序很不稳定,设备用久了总是要重启服务器程序才能恢复。新手socket,不知道是否有精通的大神,能解答一下。会不会是接收数据那段出现了问题呢,代码如下:
 class SocketThread implements Runnable {
    private Socket socket;

    public SocketThread(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStreamWriter osr = null;
        BufferedWriter bw = null;
        try {
            isr = new InputStreamReader(socket.getInputStream());
            br  = new BufferedReader(isr);
            osr = new OutputStreamWriter(socket.getOutputStream());
            bw  = new BufferedWriter(osr);
            char[] chars = new char[1024];
            int len;
            String resultMsg = "";
            while((len = br.read(chars)) != -1){
                if (1024 == len) {
                    resultMsg += chars;
                } 
                else {
                for (int i = 0; i < len; i++) {
                    resultMsg += chars[i];
                }
                resultMsg = resultMsg.trim();
                System.out.println("data:"+resultMsg);
                /**
                 * 新设备连接
                 */
                if(resultMsg.indexOf("LSKJ:")!=-1){
                    // 下面这个方法是保存socket到map中
                    ConnectNew(resultMsg, socket, bw);
                }
                /**
                 * 发送代码
                 */
                if(resultMsg.indexOf("<CODE>")!=-1){
                    // 普通客户端连接
                    int tradeCode = Integer.parseInt(SocketUtil.getXMLData(resultMsg, "CODE"));
                    switch (tradeCode) {
                    case 100:// 100代码:往设备电路板发送指令
                        String command = SocketUtil.getXMLData(resultMsg, "COMMAND");
                        String deviceIp = SocketUtil.getXMLData(resultMsg, "IP");// IP地址
                        int devicePort = Integer.parseInt(SocketUtil.getXMLData(resultMsg, "PORT")); // 端口
                        Socket sourceSocket = socketMap.get(devicePort);
                        clientMap.put(socket.getPort(), socket);
                        Writer targetWriter = new OutputStreamWriter(sourceSocket.getOutputStream());
                        targetWriter.write(command+":LSYD:"+socket.getPort());
                        targetWriter.flush();
                        break;
                    case 101:// 101代码:查询socket的数据
                        StringBuffer returnMsg = new StringBuffer();
                        if(!socketMap.isEmpty()){
                            for (Socket socket:socketMap.values()) {
                                returnMsg.append(socket.getInetAddress().getHostAddress()).append(":").append(socket.getPort());
                                returnMsg.append("\n");
                            }
                        }else{
                            returnMsg.append(" socketMap is null");
                        }
                        bw.write(returnMsg.toString());
                        bw.flush();
                        break;
                    default:
                        break;
                    }
                }
                /**
                 * 响应代码
                 */
                if(resultMsg.indexOf("LSYD:")!=-1){
                    /**
                     * 返回例子:
                     * OUDC1_??:LSYD:10001 OFF
                     */
                    String[] msg = resultMsg.split(":");
                    if(msg.length>=2){
                        String returnCommand = resultMsg.split(":")[2];
                        if(returnCommand.length()>=4){
                            // 取出返回端口号
                            returnCommand = returnCommand.substring(0, 5);
                            String regEx="[^0-9]";   
                            Pattern p = Pattern.compile(regEx);   
                            Matcher m = p.matcher(returnCommand);
                            // 端口号
                            int clientPort = Integer.parseInt(m.replaceAll("").trim());
                            //System.out.println("端口号是:"+clientPort);
                            // 返回结果
                            String result = resultMsg.substring(resultMsg.lastIndexOf(" ")+1,resultMsg.length());

                                //取出socket返回
                                Socket clientSocket = clientMap.get(clientPort);
                                if(clientSocket!=null){
                                    Writer targetWriter = new OutputStreamWriter(clientSocket.getOutputStream());
                                    targetWriter.write(result);
                                    targetWriter.flush();
                                    clientMap.remove(clientPort);
                                }

                        }
                    }
                }
                }
                resultMsg ="";
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

}
代码解释一下,当有LSKJ:00001请求的话,服务器就建立长连接,同时保存了IP和端口了,然后如果有<CODE>100</CODE><COMMAND>OUDC1_??</COMMAND><IP>192.168.1.222</IP><PORT>55775</PORT>这种信息请求的话,我就知道是要发送给指定的设备,然后等待设备返回指令OUDC1_ON=030:LSYD:54498:OK,我就知道要返回给54498端口的客户端短连接数据了。

TCP Socket连接是双向的,通过四次挥手的方式断开,双方分别调用Socket.close()方法断开连接。连接断开的过程中,一般一方A先断开连接,另一方B发现A断开连接后,也断开连接。为方便表述,将先断开连接的一方A称为“主动断开连接”;后断开的一方B,则为“被动断开连接”。

在一方B阻塞执行in.readUTF()方法时,如果对方A主动断开Socket连接,这个方法会抛出异常。从而在B处理异常时,可以被动的断开这边的连接。

为保证主动断开连接的一方不会阻塞在in.readUTF()方法中,需要先执行socket.shutdownInput()。所以主动断开连接的代码如下。

socket.shutdownInput();
in.close();
socket.close();

被动断开连接的一方,在捕获到in.readUTF()的异常后,断开Socket连接。

复制代码
try {
String s = in.readUTF();
} catch (IOException e) {
// 连接被断开(被动)
try {
in.close();
socket.close();
in = null;
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}

结合IP域名过滤好一些,像微信公众号哪样的安全认证。

我想知道,你读取的时候是怎么读的,你的代码里是socket不是socketServer端,是否有使用readLine这种等待换行符阻塞的代码,
或者因为需要等待某个结束符出现才解除阻塞的代码段(这个是解决你关掉服务器后反而会显示出之前发过来没显示的数据)。如果没有的话,
看下你的tcp有没有设置超时时间,这个一般是CPU内核的参数,TCP链接要监听下他的idle空间时间内链接的情况,如果空闲时间太长,也会断开
(你文章说这个是短连接,但是并没有具体提到客户端或者服务端主动断开连接,所以是否可以认为你依然TCP是连着的,依然是长连接),如果还是长连接,那么按照四次挥手,客户端断开了,其实服务器是不知道的,所以需要设置TCP的SO__KEEPALIVE,可以让tcp在2小时候发送一个探测报文,自己来判断是否断开连接