2 sun13rain14 sun13rain14 于 2013.11.07 17:06 提问

java socket 长连接奇怪的问题

我有一个类,负责通过SOCKET长连接与服务器端通讯。
这个循环读取一个队列来发送。
问题来了,在本类的MAIN方法中向队列中添加数据,就可以发送出去,在SERVLET中,通过HTTP请求添加,就是发送不出去!请大家帮忙看看,谢谢。下面是这个主要类的代码。

/**

  • */ package com.dianshangwang.lianhepayfront.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

import com.dianshangwang.lianhepayfront.global.Config;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**

  • @author lay
  • @date 2013年11月4日
    */
    public class IcardpayClient {
    private static Logger log = Logger.getLogger(IcardpayClient.class);
    private static Socket socket;
    private static BufferedReader reader;
    private static PrintWriter writer;
    private static Thread sendThread;
    private static Thread receiveThread;
    private static Thread monitorThread;

    private static boolean isRunning = false;

    /**

    • 心跳计数器 若此值与当前时间戳值小于60000则认定断线,进行重联操作 */ private static Long heartbeatTimestamp = System.currentTimeMillis();

    private static IcardpayClient instance = new IcardpayClient();

    private IcardpayClient() {
    }

    public static IcardpayClient getInstance() {
    return instance;
    }

    public static void main(String[] args) {
    BasicConfigurator.configure();
    IcardpayClient client = new IcardpayClient();
    client.start();

    MsgQueue.sendQueue.add("{\"agentNo\":\"A10342hp\",\"tradeType\":\"256\",\"sessionId\":\"1\"}");
    

    }

    public void start() {
    init();

    sendThread = new Thread(new SendThread());// 启动读线程
    receiveThread = new Thread(new ReceiveThread());// 启动收线程
    monitorThread = new Thread(new MonitorThread()); // 启动监视线程
    
    sendThread.setName("icardpay-send-thread");
    receiveThread.setName("icardpay-receive-thread");
    monitorThread.setName("icardpay-monitor-thread");
    

// sendThread.setDaemon(true);
// receiveThread.setDaemon(true);
// monitorThread.setDaemon(true);

    sendThread.start();
    log.info("SOCKET发送线程开启!");
    receiveThread.start();
    log.info("SOCKET接收线程开启!");
    // monitorThread.start();
    // log.info("SOCKET监视线程开启!");

}

public void restart() {
    stop();
    init();
}

public void stop() {
    isRunning = false;
}

private void init() {
    socket = new Socket();
    try {
        socket.setKeepAlive(true);
        socket.connect(new InetSocketAddress(Config.icardpayHost, Config.icardpayPort));
        reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        writer = new PrintWriter(socket.getOutputStream());

        heartbeatTimestamp = System.currentTimeMillis();

        log.info("已创建与支付通的SOCKET连接!");

        isRunning = true;
    } catch (SocketException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public void write(String msg) {
    writer.println(msg);
    writer.flush();
    log.info(Thread.currentThread().getName() + "发送:" + msg);
}

private String read() throws IOException {
    String msg = reader.readLine();
    if (msg != null) {
        log.info("接收:" + msg);
    }
    return msg;
}

class SendThread implements Runnable {

    @Override
    public void run() {

        while (isRunning) {

            if (!MsgQueue.sendQueue.isEmpty()) {

                String v = MsgQueue.sendQueue.poll();

                write(v);
            }

            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

class ReceiveThread implements Runnable {

    @Override
    public void run() {
        while (isRunning) {

            String content = null;
            try {
                content = read();
            } catch (IOException e1) {
                log.error("SOCKET读取异常,将重新启动。。。", e1);
                restart();
                continue;
            }

            if (null == content || content == "") {
                continue;
            }

            JsonObject obj = new JsonParser().parse(content).getAsJsonObject();

            if (obj.has("tradeType") && "0".equals(obj.get("tradeType").getAsString())) {
                // 收到心跳包, 刷新计数器
                heartbeatTimestamp = System.currentTimeMillis();
                continue;
            }

            if (!obj.has("sessionId")) {
                log.info("收到未标识的包:" + obj.toString());
                continue;
            }

            String id = obj.get("sessionId").getAsString();

            if (MsgQueue.listeners.containsKey(id)) {
                MsgQueue.listeners.get(id).received(content);
                MsgQueue.listeners.remove(id);
            } else {
                log.info("接收到过期包:" + content);
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 忽略
            }

        }
    }

}

class MonitorThread implements Runnable {

    String heartbeat = "{\"agentNo\":\"A10342hp\",\"tradeType\":\"0\"}";

    @Override
    public void run() {
        while (isRunning) {
            if (System.currentTimeMillis() - heartbeatTimestamp >= 60000) {
                // SOCKET已失效
                restart();
            }

            // 发送心跳包
            write(heartbeat);

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // 忽略
            }
        }
    }

}

}

1个回答

dongtianliubuzhu
dongtianliubuzhu   2013.12.04 17:19

我没怎么看代码但是你说读写的问题是不是会用到流,用流的时候要注意,对应创建。尤其在socket经过传递后,比如有一个函数的参数是socket,传到函数中建立流,那么对应的另一端也要从新建立,不能再用原来的了

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