socket客户端程序

下面是socket客户端程序,之前我做的部分内容是实现了和服务器端程序的交互,但是没有达到通过心跳包实时检测客户端和服务器端是否正常连接,在一位高手同事的帮助下完成了心跳包检测并优化了socket客户端程序,大大提高了通讯效率。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;

import com.bill99.bvc.socket.util.StreamNoGenerator;

/**
* @author Administrator
*/
/**
*<p>title: </p>
*<p>Description: </p>
*<p>CopyRight: CopyRight (c) 2009</p>
*<p>Company: 99bill.com</p>
*<p>Create date: 2009-11-12</P>
*@author Jophy
*@version v0.1 2009-10-14 鍒濈被
* v0.11 2009-11-12 瀵瑰懡浠ゆ敹鍙戦€昏緫鍙婃敹鍙戠嚎绋嬩簰鏂ユ満鍒惰繘琛屼簡浼樺寲锛屽鐞嗗懡浠ら€熷害鐢卞師鏉?~16涓?绉掓彁楂樺埌25~32涓?绉?
*/
public class SocketConnection {

private volatile Socket socket;
private int timeout = 1000*10; //瓒呮椂鏃堕棿锛屽垵濮嬪€?0绉?
private boolean isLaunchHeartcheck = false;//鏄惁宸插惎鍔ㄥ績璺虫娴?
private boolean isNetworkConnect = false; //缃戠粶鏄惁宸茶繛鎺?
private static String host = "";
private static int port;
static InputStream inStream = null;
static OutputStream outStream = null;
private static Logger log =Logger.getLogger(SocketConnection.class);
private static SocketConnection socketConnection = null;
private static java.util.Timer heartTimer=null;
//-------------------------------------------
//private final Map<String, Object> recMsgMap= Collections.synchronizedMap(new HashMap<String, Object>());
private final ConcurrentHashMap<String, Object> recMsgMap = new ConcurrentHashMap<String, Object>();
private static Thread receiveThread = null;
private final ReentrantLock lock = new ReentrantLock();

private SocketConnection(){

Properties conf = new Properties();
try {
conf.load(SocketConnection.class.getResourceAsStream("test.conf"));
this.timeout = Integer.valueOf(conf.getProperty("timeout"));
init(conf.getProperty("ip"),Integer.valueOf(conf.getProperty("port")));
} catch(IOException e) {
log.fatal("socket鍒濆鍖栧紓甯?",e);
throw new RuntimeException("socket鍒濆鍖栧紓甯?璇锋鏌ラ厤缃弬鏁?);
}
}
/**
* 鍗曟€佹ā寮?
*/
public static SocketConnection getInstance() {
if(socketConnection==null) {
synchronized(SocketConnection.class) {
if(socketConnection==null) {
socketConnection = new SocketConnection();
return socketConnection;
}
}
}
return socketConnection;
}

private void init(String host,int port) throws IOException {
InetSocketAddress addr = new InetSocketAddress(host,port);
socket = new Socket();
log.info("銆愬噯澶囦笌"+addr+"寤虹珛杩炴帴銆?);
socket.connect(addr, timeout);
log.info("銆愪笌"+addr+"杩炴帴宸插缓绔嬨€?);
inStream = socket.getInputStream();
outStream = socket.getOutputStream();
socket.setTcpNoDelay(true);//鏁版嵁涓嶄綔缂撳啿锛岀珛鍗冲彂閫?
socket.setSoLinger(true, 0);//socket鍏抽棴鏃讹紝绔嬪嵆閲婃斁璧勬簮
socket.setKeepAlive(true);
socket.setSoTimeout(timeout);
socket.setTrafficClass(0x04|0x10);//楂樺彲闈犳€у拰鏈€灏忓欢杩熶紶杈?
isNetworkConnect=true;
receiveThread = new Thread(new ReceiveWorker());
receiveThread.start();
SocketConnection.host=host;
SocketConnection.port=port;
if(!isLaunchHeartcheck)
launchHeartcheck();
}
/**
* 蹇冭烦鍖呮娴?
*/
private void launchHeartcheck() {
if(socket == null)
throw new IllegalStateException("socket is not established!");
heartTimer = new Timer();
isLaunchHeartcheck = true;
int heartdailyTime =0;
if(timeout==0){
heartdailyTime =1000 * 10;
}
if(timeout>0){
heartdailyTime =(int)(2/3F*timeout);//蹇冭烦闂存瓏鏃堕棿锛岄棿姝囨椂闂翠笉鑳藉ぇ浜巘imeout
}
heartTimer.schedule(new TimerTask() {
public void run() {
String msgCryptIndex="0000";//淇濈暀瀛楁锛屾殏涓嶄娇鐢紝缁熶竴濉€?000鈥?
String msgStreamNo = StreamNoGenerator.getStreamNo("kq");
int mstType =1161;//1161-蹇冭烦鍖呰姹?
SimpleDateFormat dateformate = new SimpleDateFormat("yyyyMMddHHmmss");
String msgDateTime = dateformate.format(new Date());
String areaNum = "000 ";//缁堢鎵€灞炵殑鏈湴缃戝尯鍙凤紝涓嶅甫0銆傚骞垮窞涓衡€?0鈥濄€傜己鐪佸€间负000锛屾爣绀轰负鐪佺骇绯荤粺
String source = "0007";//鏈秷鎭潵婧愬钩鍙版爣璇嗐€?浣嶅钩鍙版爣璇嗭紝
String target ="0001" ;//鏈秷鎭殑鐩爣骞冲彴鏍囪瘑銆?浣嶅钩鍙版爣璇?
int msgLength =621;//娑堟伅澶撮暱搴?
String commandstr = String.valueOf("00"+ msgLength) + msgCryptIndex + msgStreamNo + String.valueOf(mstType) + msgDateTime + areaNum +source +target;
log.info("蹇冭烦妫€娴嬪寘 -> IVR "+commandstr);
int reconnCounter = 1;
while(true) {
String responseMsg =null;
try {
responseMsg = readReqMsg(commandstr);
}catch(SocketException e){
log.error("socket error",e);
reconnCounter ++;
}catch (java.net.SocketTimeoutException e) {
log.error("socket time out");
reconnCounter ++;
} catch (IOException e) {
log.error("IO娴佸紓甯?,e);
reconnCounter ++;
}
if(responseMsg!=null) {
log.info("蹇冭烦鍝嶅簲鍖?<- IVR "+responseMsg);
reconnCounter = 1;
break;
} else {
reconnCounter ++;
}
if(reconnCounter >3) {//閲嶈繛娆℃暟宸茶揪涓夋锛屽垽瀹氱綉缁滆繛鎺ヤ腑鏂紝閲嶆柊寤虹珛杩炴帴銆傝繛鎺ユ湭琚缓绔嬫椂涓嶉噴鏀鹃攣
reConnectToCTCC();
}
}
}
},1000 * 80,heartdailyTime);
}

/**
* 閲嶈繛涓庡箍涓滅數淇¢噸杩?
*/
private void reConnectToCTCC() {
new Thread(new Runnable(){
public void run(){
log.info("閲嶆柊寤虹珛涓?+host+":"+port+"鐨勮繛鎺?);
//娓呯悊宸ヤ綔锛屼腑鏂鏃跺櫒锛屼腑鏂帴鏀剁嚎绋嬶紝鎭㈠鍒濆鍙橀噺
heartTimer.cancel();
isLaunchHeartcheck=false;
isNetworkConnect = false;
receiveThread.interrupt();
try {
socket.close();
} catch (IOException e1) {log.error("閲嶈繛鏃讹紝鍏抽棴socket杩炴帴鍙戠敓IO娴佸紓甯?,e1);}
//----------------
synchronized(this){
for(; ;){
try {
Thread.currentThread();
Thread.sleep(1000 * 1);
init(host,port);
this.notifyAll();
break ;
} catch (IOException e) {
log.error("閲嶆柊寤虹珛杩炴帴鏈垚鍔?,e);
} catch (InterruptedException e){
log.error("閲嶈繛绾跨▼涓柇",e);
}
}
}
}
}).start();
}

/**
* 鍙戦€佸懡浠ゅ苟鎺ュ彈鍝嶅簲
* @param requestMsg
* @return
* @throws SocketTimeoutException
* @throws IOException
*/
public String readReqMsg(String requestMsg) throws IOException {
if(requestMsg ==null) {
return null;
}
if(!isNetworkConnect) {
synchronized(this){
try {
this.wait(1000*5); //绛夊緟5绉掞紝濡傛灉缃戠粶杩樻病鏈夋仮澶嶏紝鎶涘嚭IO娴佸紓甯?
if(!isNetworkConnect) {
throw new IOException("缃戠粶杩炴帴涓柇锛?);
}
} catch (InterruptedException e) {
log.error("鍙戦€佺嚎绋嬩腑鏂?,e);
}
}
}
String msgNo = requestMsg.substring(8, 8 + 24);//璇诲彇娴佹按鍙?
outStream = socket.getOutputStream();
outStream.write(requestMsg.getBytes());
outStream.flush();
Condition msglock = lock.newCondition(); //娑堟伅閿?
//娉ㄥ唽绛夊緟鎺ユ敹娑堟伅
recMsgMap.put(msgNo, msglock);
try {
lock.lock();
msglock.await(timeout,TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.error("鍙戦€佺嚎绋嬩腑鏂?,e);
} finally {
lock.unlock();
}
Object respMsg = recMsgMap.remove(msgNo); //鍝嶅簲淇℃伅
if(respMsg!=null &&(respMsg != msglock)) {
//宸茬粡鎺ユ敹鍒版秷鎭紝娉ㄩ攢绛夊緟锛屾垚鍔熻繑鍥炴秷鎭?
return (String) respMsg;
} else {
log.error(msgNo+" 瓒呮椂锛屾湭鏀跺埌鍝嶅簲娑堟伅");
throw new SocketTimeoutException(msgNo+" 瓒呮椂锛屾湭鏀跺埌鍝嶅簲娑堟伅");
}
}

public void finalize() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//娑堟伅鎺ユ敹绾跨▼
private class ReceiveWorker implements Runnable {
String intStr= null;
public void run() {
while(!Thread.interrupted()){
try {
byte[] headBytes = new byte[4];
if(inStream.read(headBytes)==-1){
log.warn("璇诲埌娴佹湭灏撅紝瀵规柟宸插叧闂祦!");
reConnectToCTCC();//璇诲埌娴佹湭灏撅紝瀵规柟宸插叧闂祦
return;
}
byte[] tmp =new byte[4];
tmp = headBytes;
String tempStr = new String(tmp).trim();
if(tempStr==null || tempStr.equals("")) {
log.error("received message is null");
continue;
}
intStr = new String(tmp);
int totalLength =Integer.parseInt(intStr);
//----------------
byte[] msgBytes = new byte[totalLength-4];
inStream.read(msgBytes);
String resultMsg = new String(headBytes)+ new String(msgBytes);
//鎶藉嚭娑堟伅ID
String msgNo = resultMsg.substring(8, 8 + 24);
Condition msglock =(Condition) recMsgMap.get(msgNo);
if(msglock ==null) {
log.warn(msgNo+"搴忓彿鍙兘宸茶娉ㄩ攢锛佸搷搴旀秷鎭涪寮?);
recMsgMap.remove(msgNo);
continue;
}
recMsgMap.put(msgNo, resultMsg);
try{
lock.lock();
msglock.signalAll();
}finally {
lock.unlock();
}
}catch(SocketException e){
log.error("鏈嶅姟绔叧闂璼ocket",e);
reConnectToCTCC();
} catch(IOException e) {
log.error("鎺ユ敹绾跨▼璇诲彇骞夸笢鐢典俊鍝嶅簲鏁版嵁鏃跺彂鐢烮O娴佸紓甯?,e);
} catch(NumberFormatException e){
log.error("鏀跺埌娌¤壇蹇冨寘锛孲tring杞琲nt寮傚父锛屽紓甯稿瓧绗?"+intStr);
try {
//娓呯┖娌¤壇蹇冨寘鐨勫墿浣欏瓧绗?
int packageNum = inStream.available();
inStream.skip(packageNum);
log.info("娓呯┖鍓╀綑瀛楄妭鏁?"+packageNum);
} catch(IOException ex){log.error("娓呯┖娌¤壇蹇冨寘鍓╀綑瀛楄妭鍑洪敊",ex);}
}
}
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值