socket使用2

package com.sf.dtx5.request;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;

import com.sf.dtx5.Config;
import com.sf.dtx5.domain.PubFun;
import com.sf.dtx5.reponse.CRequest_ApplyToCustomsCheck;
import com.sf.dtx5.reponse.CRequest_AutoUpdate;
import com.sf.dtx5.reponse.CRequest_CheckNewClientVersion;
import com.sf.dtx5.reponse.CRequestDownAllProduct;
import com.sf.dtx5.reponse.CRequest_DownloadBillFirst;
import com.sf.dtx5.reponse.CRequest_DownloadBillIncrement;
import com.sf.dtx5.reponse.CRequest_DownloadBillWantedCompatible;
import com.sf.dtx5.reponse.CRequest_DownloadBillWantedIncrement;
import com.sf.dtx5.reponse.CRequest_DownloadBulkConfig;
import com.sf.dtx5.reponse.CRequest_DownloadDefaultMap;
import com.sf.dtx5.reponse.CRequest_DownloadDestCityCode;
import com.sf.dtx5.reponse.CRequest_DownloadExpBill;
import com.sf.dtx5.reponse.CRequest_DownloadExpConfig;
import com.sf.dtx5.reponse.CRequest_DownloadFile;
import com.sf.dtx5.reponse.CRequest_DownloadFileCount;
import com.sf.dtx5.reponse.CRequest_DownloadIdentRsFull;
import com.sf.dtx5.reponse.CRequest_DownloadLineCodes;
import com.sf.dtx5.reponse.CRequest_DownloadOpattachList;
import com.sf.dtx5.reponse.CRequest_DownloadOutBil2lIncrement;
import com.sf.dtx5.reponse.CRequest_DownloadOutBill;
import com.sf.dtx5.reponse.CRequest_DownloadOutBill2;
import com.sf.dtx5.reponse.CRequest_DownloadReasonCodeConfig;
import com.sf.dtx5.reponse.CRequest_DownloadTaskInfo;
import com.sf.dtx5.reponse.CRequest_DownloadUsersList;
import com.sf.dtx5.reponse.CRequest_FromBarGetpackage;
import com.sf.dtx5.reponse.CRequest_QueryOnline;
import com.sf.dtx5.reponse.CRequest_UploadBill;
import com.sf.dtx5.reponse.CRequest_UploadImage;
import com.sf.dtx5.reponse.CRequestDownRealTask;
import com.sf.dtx5.reponse.CRequestForceNewClientVersion;
import com.sf.dtx5.reponse.CRequest_UserLogion;
import com.sf.dtx5.reponse.CRequest_WantedBill;
import com.sf.dtx5.reponse.CRequest_billroute;
import com.sf.dtx5.reponse.CRequest_webserviceAddress;
import com.sf.dtx5.reponse.IRequestCommand;
import com.sf.dtx5.util.ParseProperties;

/**
 * 每个Socket命令数据的处理
 */
public class CThreadSocketWorkingBar extends Thread {
	private Socket socket;// socket通信
	private String ipaddr;// ip地址

	public CThreadSocketWorkingBar(Socket socket) {
		super();
		this.socket = socket;
		try {
			// 设置socket超时,单位:毫秒
			ipaddr = socket.getRemoteSocketAddress().toString();
			socket.setSoTimeout(Config.getSocketTimeout() * 1000);
		} catch (Exception e) {
			Config.log.writeLog(2, "设置socket超时错误:%s", e);
		}
	}
    @Override
	public void run() {
		try {
			Config.log.writeLog(3, "巴枪进入:%s [Socket在线数:%d]", ipaddr,
					CThreadSocketListen.getOnlineCount(true));
			// 版本信息
			byte[] ver = new byte[2];
			StringBuilder sbuf = new StringBuilder();
			while (readCommandData(sbuf, ver)) {
				long s1 = System.currentTimeMillis();
				Config.log.writeLog(3, "巴枪进入:%s [Socket命令用时为>:%s]", ipaddr,
						sbuf.toString());
				interpreterCommand(sbuf.toString(), ver);
				long s2 = System.currentTimeMillis();
				char cmdChar = sbuf.toString().charAt(12);
				if(cmdChar=='U'){
					Config.log.writeLog(3, "巴枪进入:%s [Socket命令用时是>:%s]", ipaddr,
							"U" + " use Time: " + (s2-s1));	
				}else{
					Config.log.writeLog(3, "巴枪进入:%s [Socket命令用时间>:%s]", ipaddr,
							sbuf.toString() + " use Time: " + (s2-s1));	
				}
						
			}
			Config.log.writeLog(3, "巴枪退出:%s [Socket在线数:%d]", ipaddr,
					CThreadSocketListen.getOnlineCount(false));
		} finally {
			if (null != socket && !socket.isClosed()) {
				try {
					socket.close();
				} catch (Exception e1) {
					Config.log.writeLog(2, "socket关闭时错误:%s", e1);
				}
			}
		}
		
		
	}

	/**
	 * 读取命令数据
	 * 
	 * @param sbuf
	 *            返回命令数据
	 */
	private boolean readCommandData(StringBuilder sbuf, byte[] ver) {
		// 读取命令数据格式:1位校验码+1位0+2位版本号+4位数据包长度+12位机器代码+1位命令+n位附加数据
		try {
			byte[] buftmp = new byte[4];
			InputStream is=socket.getInputStream();
			DataInputStream in = new DataInputStream(is);
			Config.log.writeLog(4,"start recieve message1--" + ipaddr);
			int flag = 0;
			byte[] bufwbep = new byte[8];
			flag = in.read(bufwbep,0,8);//读取前八位,不影响之前的流程
			StringBuilder strbuff = new StringBuilder();
			
			if(flag != -1){//对于图片上传WBEP,特殊处理...sfit0336-----------------------start----------------
				for(int i=4;i< bufwbep.length;i++){
					strbuff.append((char)bufwbep[i]);
				}
				if(strbuff.toString().equals("0000")){//传输类似:e1  000000000,所以截取后四位
					BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			            String line = "";
			            while ((line = reader.readLine()) != null) {
			            	sbuf.append(line);
			            }
					return true;
				}//对于图片上传WBEP,特殊处理...sfit0336-----------------------end----------------
			}
			
			if(flag != -1){
				byte bVerify = bufwbep[0];// 校验码
				ver[0] = bufwbep[2];// 版本号
				ver[1] = bufwbep[3];// 版本号
				
				Config.log.writeLog(4,"enter into recieve message2--" + ipaddr);
				buftmp[0] = bufwbep[4];
				buftmp[1] = bufwbep[5];
				buftmp[2] = bufwbep[6];
				buftmp[3] = bufwbep[7];
				
				int len = (buftmp[0] & 0x0ff) + (buftmp[1] & 0x0ff) * 256
						+ (buftmp[2] & 0x0ff) * 256 * 256
						+ (buftmp[3] & 0x0ff) * 256 * 256 * 256;
				// 命令最大长度为16MB
				if ((len > 0) && (len <= 1024 * 1024 * 16)) {
					byte[] cmdbuf = new byte[len - 8];
					
				if(flag != -1&&bufwbep[1]==1){//对于图片上传OPQM,特殊处理...sfit0336-----------------------start----------------
						
							 byte[] buffer=new byte [1024];
							 int length =0;
							while(true){
								int size = is.read(buffer);
								if(size >0){
									length+=size;
									String str=new String(buffer,0,size,"UTF-8");
									sbuf.append(str);
								}
								if (length==cmdbuf.length){
									break;
								}
							}
							return true;//对于图片上传OPQM,特殊处理...sfit0336-----------------------end----------------
					}
					
					
					
					if (-1 != in.read(cmdbuf, 0, cmdbuf.length)) {
						if (PubFun.getBufferSumCheck(PubFun
								.getBufferSumCheck((byte) 0, buftmp, 0, 4),
								cmdbuf, 0, cmdbuf.length) == bVerify) {// 通过校验
							sbuf.delete(0, sbuf.length());// 清空
							sbuf.append(new String(cmdbuf,"UTF-8"));// 装载除前8位的数据
						/**	for (int i = 0; i < cmdbuf.length; i++) {
								sbuf.append((char) cmdbuf[i]);// 装载除前8位的数据
							}*/
							return true;
						} else {
							Config.log.writeLog(3,"收到来自[%s]的错误命令:校验错误!(%d)%s", ipaddr,
									len, sbuf.toString());
						}
					}
					Config.log.writeLog(4,"enter into recieve message3--" + ipaddr);
				}				
				
			}
		} catch (SocketTimeoutException e) {
			Config.log.writeLog(3, "终端已锁屏:%s--%s", ipaddr,e);
		} catch (Exception e) {
			Config.log.writeLog(2, "解析命令时错误:%s--%s",ipaddr, e);
		}
		return false;
	}

	/**
	 * 处理命令
	 * 
	 * @param cmdstr
	 *            命令数据
	 * @param ver
	 *            版本號
	 */
	private void interpreterCommand(String cmdstr, byte[] ver) {// 命令数据格式:12位机器代码+1位命令+n位附加数据
		if(cmdstr.length()>16&&cmdstr.substring(13, 16).equals("39,")){
			Config.log.writeLog(2, "uploadImage--[拍照上传OPQM]--");
		}else if(cmdstr.length() > 13){
			int startIndex = cmdstr.indexOf(',');
			if(startIndex>=17){
				String str1 = cmdstr.substring(startIndex);
				String []temp = cmdstr.split(",");
				String temp1 = temp[0].replaceAll(" ", "");
				String temp2 =temp1;
				if(temp1.length()>=17 ){
					temp1 = temp1.substring(temp1.length()-13, temp1.length());
					if(temp2.substring(0,4).equals("0000")){
						cmdstr = temp1+str1;
						Config.log.writeLog(2, "uploadImage--[拍照上传WBEP]--");
					}
				}
			}
		}
		
		if (cmdstr.length() > 12) {
			char cmdChar = cmdstr.charAt(12);
			IRequestCommand r = getRequestCommand(cmdChar);
			if (r != null) {
				long a = System.currentTimeMillis();
				if(cmdChar=='U'){
					Config.log.writeLog(3, "收到来自[%s]的命令:%s", ipaddr, "U");
				}else{
					Config.log.writeLog(3, "收到来自[%s]的命令:%s", ipaddr, cmdstr);
				}
				

				int clientver = ver[0] * 16 + ver[1];
				//20161209  登陆命令版本号做特殊处理
				if(cmdChar=='L'){
					clientver = ver[0] * 256 + ver[1];
				}
				byte[] date;
				try {
					date = r.responses(cmdstr, clientver);
				} catch (Exception e) {
					date = null;
					e.printStackTrace();
					Config.log.writeLog(3, "处理来自[%s]的命令错误:%s %s", ipaddr,
							cmdstr, e);
				}
				if (date != null) {
					ByteBuffer buffer = ByteBuffer.allocate(8 + date.length);
					buffer.put((byte) 0);
					buffer.put((byte) 0);
					buffer.put((byte) 0);
					buffer.put((byte) 0);
					buffer.putInt(Integer.reverseBytes(buffer.capacity()));
					buffer.put(date);
					date = buffer.array();
					date[0] = PubFun.getBufferSumCheck((byte) 0, date, 0,
							date.length);
					if (clientver >= (2 * 16 + 2)) {// 客户端V2.2以上处理
						date[2] = Config.getServerversion()[0];
						date[3] = Config.getServerversion()[1];
					}
				} else {
					try {
						date = "null".getBytes(ParseProperties.getValue("character_code"));
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
				}
				long b = System.currentTimeMillis();
				Config.log.writeLog(4, "巴枪进入:%s [Socket命令用时>:%s]", ipaddr,
						cmdstr + " server use Time: " + (b-a));	
				try {
					DataOutputStream out = new DataOutputStream(
							socket.getOutputStream());
					if(cmdChar=='U'){
						out.write(date);
						out.flush();
						socket.shutdownOutput();
					}else{
						out.write(date);
						out.flush();
					}
					if(date!=null){
						Config.log.writeByteTo0x16Format(4, "发送数据:", date,
								date.length);
					}
				} catch (Exception e) {
					e.printStackTrace();
					Config.log.writeLog(3, "发送数据到[%s]失败:%s", ipaddr, e);
				}
				long c = System.currentTimeMillis();
				Config.log.writeLog(4, "巴枪进入:%s [Socket命令用时>:%s]", ipaddr,
						cmdstr + " trans use Time: " + (c-b));	
			} else {
				Config.log.writeLog(2, "收到来自[%s]的错误命令:%s", ipaddr, cmdstr);
			}
		} else {
			Config.log.writeLog(2, "收到来自[%s]的错误命令:%s", ipaddr, cmdstr);
		}
	}
	

	/**
	 * 取得命令对应服务
	 * 
	 * @param cmd
	 *            命令字
	 * @return
	 */
	private IRequestCommand getRequestCommand(char cmd) {
		switch (cmd) {
			case 'F':// 初始化DTX5
				return new CRequest_DownloadBillFirst();
			case 'P':// 增量下载
			case 'D':
			case 'd'://sfit0336 billroute表增加字段:area_code
			case 'X':
			case 'x':
			case 'e'://sfit0336 billroute表增加字段:product_code
				return new CRequest_DownloadBillIncrement();
			//和D命令一样,只是增加一个映射前的网点代码用于装车
			/**return new CRequest_DownloadBillIncrement2();*/
			case 'Y':// 旧版本,查询下载文件数
				return new CRequest_DownloadFileCount();
			case 'Z':// 旧版本,下载文件
				return new CRequest_DownloadFile();
			case 'L':// 用户登录
				return new CRequest_UserLogion();
			case 'M':// 上传操作记录
				return new CRequest_UploadBill();
			case 'N':// 下载用户列表
				return new CRequest_DownloadUsersList();
			case 'J':// 自动更新主程序
				return new CRequest_AutoUpdate();
			case 'W':// 通辑件
				return new CRequest_WantedBill();
			case 'V':// 版本检测
				return new CRequest_CheckNewClientVersion();
			case 'O':// 下载线路编码列表
				return new CRequest_DownloadOpattachList();
			case 'Q':// 在线信息查询,用于快速查询
				return new CRequest_QueryOnline();
			case 'R':// 报关检测
				if (Config.isOpenapplytocustoms()) {// 启用了统一报关
					return new CRequest_ApplyToCustomsCheck();
				}
				break;
			case 'A':
				return new CRequest_billroute();
			case 'T'://COD下载地址
				return new CRequest_webserviceAddress();
			case 'E'://异常原因运单
			case 'B':
				return new CRequest_DownloadExpBill();
			case 'C'://异常原因配置
				return new CRequest_DownloadExpConfig();
			case 'i'://滞留原因配置
				return new CRequest_DownloadReasonCodeConfig();
			case 'G'://自动获取包牌号
			case 'j'://自动获取笼号
			case 'm'://自动获取车标号
				return new CRequest_FromBarGetpackage();	
			case 'I'://下载线路编码
				return new CRequest_DownloadLineCodes();				
			case 'K'://下载出港运单数据
				return new CRequest_DownloadOutBill();	
			case 'k'://下载出港运单数据
				return new CRequest_DownloadOutBill2();				
			case 'H'://出港识别到片区配置
				return new CRequest_DownloadDefaultMap();
			case 'S'://出港识别到片
			case 's':
				return new CRequest_DownloadOutBil2lIncrement();				
			case 'w':// 通辑件
				return new CRequest_DownloadBillWantedIncrement();
			case 'f':// 通辑件-- 增加的字段info sfit0336 varchar2(20)
			case 'c':// 通辑件-- 增加的字段info sfit0336 varchar2(30)
			case 'n':
				return new CRequest_DownloadBillWantedCompatible();
			case 'a':// 下载进出港bar枪校验配置transit_flow(1000) 将被'b'命令替换
			case 'b':// 下载进出港bar枪校验配置transit_flow(1000) 增加线路编码长度到24 兼容'a'命令
			case 'l':
				return new CRequest_DownloadDestCityCode();	
			case 'U':// 下载图片记录流水,并上传sfit0336
				return new CRequest_UploadImage();
			case 'h':// 网点代码与中转场配置 80000336
				return new CRequest_DownloadBulkConfig();
			case 'g':// 获取识别结果全量信息下发 80000336
				return new CRequest_DownloadIdentRsFull();
			case 'o':
			case 'p':
				return new CRequest_DownloadTaskInfo();
			case 'z'://进出港实时查询
				return new CRequestDownRealTask();
			case '0':
			case '1':
			case '2'://全货机
				return new CRequestDownAllProduct();
			case 'v':// 强制版本升级
				return new CRequestForceNewClientVersion();
			default:
			    break;
		}
		return null;
	}
}

  

posted @ 2017-12-19 18:19  杯子茶壶  阅读(85)  评论(0)    收藏  举报