下面就是Java Socket通信技术在解决收发线程互斥的代码介绍。
1.package com.bill99.svr;
2.import java.io.IOException;
3.import java.io.InputStream;
4.import java.io.OutputStream;
5.import java.net.InetSocketAddress;
6.import java.net.Socket;
7.import java.net.SocketException;
8.import java.net.SocketTimeoutException;
9.import java.text.SimpleDateFormat;
10.import java.util.Date;
11.import java.util.Properties;
12.import java.util.Timer;
13.import java.util.TimerTask;
14.import java.util.concurrent.ConcurrentHashMap;
15.import java.util.concurrent.TimeUnit;
16.import java.util.concurrent.locks.Condition;
17.import java.util.concurrent.locks.ReentrantLock;
18.import org.apache.log4j.Logger;
19./**
20.
*<p>title: socket通信包装类</p>
21.
*<p>Description: </p>
22.
*<p>CopyRight: CopyRight (c) 2009</p>
23.
*<p>Company: 99bill.com</p>
24.
*<p>Create date: 2009-10-14</P>
25.
*author sunnylocus<A href="mailto:
[email protected]">
26.
</A> * v0.10 2009-10-14 初类
27.* v0.11 2009-11-12 对命令收发逻辑及收发线程互斥机制进行了优化,
处理命令速度由原来8~16个/秒提高到25~32个/秒
28.*/ public class SocketConnection {
29.private volatile Socket socket;
30.
private int timeout = 1000*10; //超时时间,初始值10秒
31.
private boolean isLaunchHeartcheck = false;//是否已启动心跳检测
32.
private boolean isNetworkConnect = false; //网络是否已连接
33.
private static String host = "";
34.private static int port;
35.
static InputStream inStream = null;
36.
static OutputStream outStream = null;
37.
private static Logger log =Logger.getLogger
(SocketConnection.class);
38.
private static SocketConnection socketConnection = null;
39.
private static java.util.Timer heartTimer=null;
40.
//private final Map<String, Object> recMsgMap= Collections.
synchronizedMap(new HashMap<String, Object>());
41.
private final ConcurrentHashMap<String, Object> recMsgMap
= new ConcurrentHashMap<String, Object>();
42.
private static Thread receiveThread = null;
43.
private final ReentrantLock lock = new ReentrantLock();
44.private SocketConnection(){
45.
Properties conf = new Properties();
46.try {
47.conf.load(SocketConnection.class.getResourceAsStream
("test.conf"));
48.
this.timeout = Integer.valueOf(conf.getProperty("timeout"));
49.init(conf.getProperty("ip"),Integer.valueOf
(conf.getProperty("port")));
50.} catch(IOException e) {
51.log.fatal("socket初始化异常!",e);
52.throw new RuntimeException("socket初始化异常,请检查配置参数");
53.}
54.}
55./**
56.* 单态模式
57.*/
58.public static SocketConnection getInstance() {
59.
if(socketConnection==null) {
60.synchronized(SocketConnection.class) {
61.
if(socketConnection==null) {
62.
socketConnection = new SocketConnection();
63.return socketConnection;
64.}
65.}
66.}
67.return socketConnection;
68.}
69.private void init(String host,int port) throws IOException {
70.
InetSocketAddress addr = new InetSocketAddress(host,port);
71.
socket = new Socket();
72.synchronized (this) {
73.log.info("【准备与"+addr+"建立连接】");
74.socket.connect(addr, timeout);
75.log.info("【与"+addr+"连接已建立】");
76.
inStream = socket.getInputStream();
77.
outStream = socket.getOutputStream();
78.socket.setTcpNoDelay(true);//数据不作缓冲,立即发送
79.socket.setSoLinger(true, 0);//socket关闭时,立即释放资源
80.socket.setKeepAlive(true);
81.socket.setTrafficClass(0x04|0x10);//高可靠性和最小延迟传输
82.
isNetworkConnect=true;
83.
receiveThread = new Thread(new ReceiveWorker());
84.receiveThread.start();
85.
SocketConnection.host=host;
86.
SocketConnection.port=port;
87.if(!isLaunchHeartcheck)
88.launchHeartcheck();
89.}
90.}
91./**
92.* 心跳包检测
93.*/
94.private void launchHeartcheck() {
95.
if(socket == null)
96.throw new IllegalStateException("socket is not
established!");
97.
heartTimer = new Timer();
98.
isLaunchHeartcheck = true;
99.heartTimer.schedule(new TimerTask() {
100.public void run() {
101.
String msgStreamNo = StreamNoGenerator.getStreamNo("kq");
102.
int mstType =9999;//999-心跳包请求
103.
SimpleDateFormat dateformate = new SimpleDateFormat
("yyyyMMddHHmmss");
104.
String msgDateTime = dateformate.format(new Date());
105.
int msgLength =38;//消息头长度
106.
String commandstr = "00" +msgLength + mstType + msgStreamNo;
107.
log.info("心跳检测包 -> IVR "+commandstr);
108.
int reconnCounter = 1;
109.while(true) {
110.
String responseMsg =null;
111.try {
112.
responseMsg = readReqMsg(commandstr);
113.} catch (IOException e) {
114.log.error("IO流异常",e);
115.reconnCounter ++;
116.}
117.if(responseMsg!=null) {
118.
log.info("心跳响应包 <- IVR "+responseMsg);
119.
reconnCounter = 1;
120.break;
121.} else {
122.reconnCounter ++;
123.}
124.
if(reconnCounter >3) {//重连次数已达三次,判定网络连接中断,
重新建立连接。连接未被建立时不释放锁
125.reConnectToCTCC(); break;
126.}
127.}
128.}
129.},1000 * 60*1,1000*60*2);
130.}
131./**
132.* 重连与目标IP建立重连
133.*/
134.private void reConnectToCTCC() {
135.new Thread(new Runnable(){
136.public void run(){
137.log.info("重新建立与"+host+":"+port+"的连接");
138.//清理工作,中断计时器,中断接收线程,恢复初始变量
139.heartTimer.cancel();
140.
isLaunchHeartcheck=false;
141.
isNetworkConnect = false;
142.receiveThread.interrupt();
143.try {
144.socket.close();
145.} catch (IOException e1) {log.error("重连时,关闭socket连
接发生IO流异常",e1);}
146.//----------------
147.synchronized(this){
148.for(; ;){
149.try {
150.Thread.currentThread();
151.Thread.sleep(1000 * 1);
152.init(host,port);
153.this.notifyAll();
154.break ;
155.} catch (IOException e) {
156.log.error("重新建立连接未成功",e);
157.} catch (InterruptedException e){
158.log.error("重连线程中断",e);
159.}
160.}
161.}
162.}
163.}).start();
164.}
165./**
166.* 发送命令并接受响应
167.* @param requestMsg
168.* @return
169.* @throws SocketTimeoutException
170.* @throws IOException
171.*/
172.public String readReqMsg(String requestMsg) throws IOException {
173.
if(requestMsg ==null) {
174.return null;
175.}
176.if(!isNetworkConnect) {
177.synchronized(this){
178.try {
179.this.wait(1000*5); //等待5秒,如果网络还没有恢复,抛出IO流异常
180.if(!isNetworkConnect) {
181.throw new IOException("网络连接中断!");
182.}
183.} catch (InterruptedException e) {
184.log.error("发送线程中断",e);
185.}
186.}
187.}
188.
String msgNo = requestMsg.substring(8, 8 + 24);//读取流水号
189.
outStream = socket.getOutputStream();
190.outStream.write(requestMsg.getBytes());
191.outStream.flush();
192.
Condition msglock = lock.newCondition(); //消息锁
193.//注册等待接收消息
194.recMsgMap.put(msgNo, msglock);
195.try {
196.lock.lock();
197.msglock.await(timeout,TimeUnit.MILLISECONDS);
198.} catch (InterruptedException e) {
199.log.error("发送线程中断",e);
200.} finally {
201.lock.unlock();
202.}
203.
Object respMsg = recMsgMap.remove(msgNo); //响应信息
204.if(respMsg!=null &&(respMsg != msglock)) {
205.//已经接收到消息,注销等待,成功返回消息
206.return (String) respMsg;
207.} else {
208.log.error(msgNo+" 超时,未收到响应消息");
209.throw new SocketTimeoutException(msgNo+" 超时,未收到响应消息");
210.}
211.}
212.public void finalize() {
213.if (socket != null) {
214.try {
215.socket.close();
216.} catch (IOException e) {
217.e.printStackTrace();
218.}
219.}
220.}
221.//消息接收线程
222.private class ReceiveWorker implements Runnable {
223.
String intStr= null;
224.public void run() {
225.while(!Thread.interrupted()){
226.try {
227.
byte[] headBytes = new byte[4];
228.if(inStream.read(headBytes)==-1){
229.log.warn("读到流未尾,对方已关闭流!");
230.reConnectToCTCC();//读到流未尾,对方已关闭流
231.return;
232.}
233.
byte[] tmp =new byte[4];
234.
tmp = headBytes;
235.
String tempStr = new String(tmp).trim();
236.
if(tempStr==null || tempStr.equals("")) {
237.log.error("received message is null");
238.continue;
239.}
240.
intStr = new String(tmp);
241.
int totalLength =Integer.parseInt(intStr);
242.//----------------
243.
byte[] msgBytes = new byte[totalLength-4];
244.inStream.read(msgBytes);
245.
String resultMsg = new String(headBytes)+ new
String(msgBytes);
246.//抽出消息ID
247.
String msgNo = resultMsg.substring(8, 8 + 24);
248.
Condition msglock =(Condition) recMsgMap.get(msgNo);
249.
if(msglock ==null) {
250.log.warn(msgNo+"序号可能已被注销!响应消息丢弃");
251.recMsgMap.remove(msgNo);
252.continue;
253.}
254.recMsgMap.put(msgNo, resultMsg);
255.try{
256.lock.lock();
257.msglock.signalAll();
258.}finally {
259.lock.unlock();
260.}
261.}catch(SocketException e){
262.log.error("服务端关闭socket",e);
263.reConnectToCTCC();
264.} catch(IOException e) {
265.log.error("接收线程读取响应数据时发生IO流异常",e);
266.} catch(NumberFormatException e){
267.log.error("收到没良心包,String转int异常,异常字符:"+intStr);
268.}
269.}
270.}
271.}
272.}