rodhai 2018-07-16 04:14 采纳率: 50%
浏览 577
已结题

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端口的客户端短连接数据了。
  • 写回答

3条回答

  • 银河曼巴 2018-07-16 04:28
    关注

    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();
    }
    }

    评论

报告相同问题?

悬赏问题

  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 用matlab 设计一个不动点迭代法求解非线性方程组的代码
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试