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;
}
}