Socket通信技术收发线程互斥的解决方法

Java Socket通信技术在很长的时间里都在使用,在不少的程序员眼中都有很多高的评价。那么下面我们就看看如何才能掌握这门复杂的编程语言,希望大家在今后的Java Socket通信技术使用中有所收获。

下面就是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> recMsgMapCollections.
    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 intStrnull;   
  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. }   

你可能感兴趣的:(Socket通信技术收发线程互斥的解决方法)