目前在做一个c/s的项目·····
做socket通信模块   要传十六进制的数据包····
就是那种上位机变成
例如这样的数据包    0x4c 0x53 0x10 0x00 0x00 0x01 0x02 0x00 0x01 0x00 sum 0x0d 0x0a
这其中   0x4c 0x53是包头       0x0d 0x0a是包尾
这2个是固定不变的!
紧跟着包头的0x10是命令字,也就是说明这个数据包是发的什么类型的指令的,比如开机、关机什么的
然后是0x00  这个不用管,所有的命令字后面都带一个这个···  可以视为命令字的一部分
再然后就是集中器地址和包长了,这个我暂时还界定的不很清楚·····
然后就是sum   这个其实是有值的,并且这个是数据包的校验码!
这个的值是除了包头包尾以外所有值得代数和。
求大神指导一下。
我这里暂定的是写一个Byte的数组,然后一个一个从里面取出来判断
包头和包尾暂时已经搞定了····
但剩下的一些还没想好应该怎么做,求大神帮助,小弟才工作,还在试用期,不想丢工作啊!
谢谢各位了!

解决方案 »

  1.   

    中间的结构不太清楚。最好拿一个具体的二进制数据包,讲一下格式.思路,
    1. 将二进制解析为对象,
    2. 对对象进行sum校验,
    3. 分发消息.(关机,开机,其他)
      

  2.   

    我提几个建议:
    1、基础结构上,需要有以下一些东西:
       a、负责接受数据的,比如一个线程。接受后的数据放在一个byte缓冲里。用队列。
       b、拆包的。这里面可以再分成两个步骤:首先按照包头包尾拆包。需要主意的是,如果你发现收到了不完整的包,那么需要把已经从队列中取出的数据反向压回去。拆包后,可以验证以下校验和。如果不对的话,就可以直接扔了。第二步,拆包后,再解析。也就是把拆包结果转化为数据对象,比如消息对象。这时,你已经知道消息类型和其中的数据了。拆包后的数据可以放在一个缓冲里,比如list,也可以直接处理。
       c、处理消息的代码。可以为每一种消息创建一个消息处理类。处理后,如果有返回消息要封装成对象,并压入发送缓冲。
       d、发送消息的代码,可能是一个线程。从发送队列中取出需要发送的消息并转化为byte数组发出去。需要小心的问题:
    1、消息结构,如果能用定长最好,这样会减少解析复杂度。
    2、大小端的问题要约定好。
    3、需要自己搞一些基础件,比如byte数组转换为int,int转换为byte数组之类的。这些基础件一定要经过充分测试,否则,后果是灾难性的。
    4、操作容器类要小心迭代过程中不能修改容器。
    大概就是这样,不难。
      

  3.   

    我觉得socket通信,首先要解决,收到的数据是不是完整的,如果是完整的,那就不存在那么多问题了,我做的socket通信,用到的数据包,都是包头的前几个byte值表示这个数据包的长度,程序在收包时按这个长度进行读取。你要先确保你收到的数据包是完整的,这是我的建议,你参考下
      

  4.   

    我现在写了一些方法来判断这个,但是依旧是有问题的。能留个QQ不?  我直接QQ上问···
      

  5.   

    思路,
    1. 将二进制解析为对象,
    2. 对对象进行sum校验,
    3. 分发消息.(关机,开机,其他)
      

  6.   

    我把代码贴出来   大家帮忙看看···
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Timer;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class EchoServer {
    //端口号
    private int port=3005;  
    //
    private ServerSocket serverSocket;  
    private ExecutorService executorService;
    private final int POOL_SIZE = 4;
    private HashMap<String, Socket> SocketHashMap = new HashMap<String,Socket>();
    private HashSet<String> CcidHashSet = new HashSet<String>();
    byte Packet_Head[]={0x4c,0x53};
    byte Packet_End[]={0x0d,0x0a};

    public EchoServer() throws IOException { 
    Timer quTimer = new Timer();
    QueryTimerTask queryTimerTask = new QueryTimerTask(SocketHashMap, CcidHashSet);
    quTimer.scheduleAtFixedRate(queryTimerTask, 0, 30000);

    serverSocket = new ServerSocket(port);
    executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);
    // new ServerHook(executorService);  //关闭钩子
    System.out.println("服务器启动");  
    }
    public void service() {    
    while (true) {      
    Socket socket=null;      
    try {        
    socket = serverSocket.accept();      //接收客户连接  
    //socket.setSoTimeout(10000);         //10秒无数据传输,连接自动断掉
    socket.setSoTimeout(100000); 
    executorService.execute(new Handler(socket));   //创建一个工作线程  ,加入到线程池      
    }catch (IOException e) {         
    e.printStackTrace();      
    }    
    }  

    class Handler implements Runnable{
    private Socket socket;
    private InputStream br;
    private OutputStream pw;
    private byte reciver_buffer []=new byte [2048]; 
    private int recive_length;
    boolean login_succed = false;
    int ccid;

    public Handler(Socket socket){
    this.socket = socket;
    }

    public int indexOf(byte data[],int length_a,byte b[],int length_b){
    int i,j;
    for(i=0;i<=(length_a-length_b);i++){
    boolean isValid=true;
    for(j=0;j<length_b;j++){
    if(data[i+j]!=b[j]){
    isValid=false;
    break;
    }
    }
    if(isValid){
    return i;
    }
    }
    return -1; }
    public void run(){
    Socket sendSocket =null;
    try{
    System.out.println("New connection accepted"+
    socket.getInetAddress()+":"+socket.getPort());
    br = socket.getInputStream();
    pw = socket.getOutputStream();
    // BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(br));
    // String str = null;
    //     while((str=bufferedReader.readLine())!=null)
        while(true){
           recive_length=br.read(reciver_buffer, 0, 2048);
           if(recive_length!=-1){
    //    for(int i=0;i<recive_length;i++){
    // int temp = 0xff & reciver_buffer[i]; 
    // System.out.println(Integer.toHexString(temp));
    // }
     int index_head=indexOf(reciver_buffer,reciver_buffer.length,Packet_Head,Packet_Head.length);  
     System.out.println("packet_head index is:"+index_head);
     if(index_head==-1) continue;
     int index_end=indexOf(reciver_buffer,reciver_buffer.length,Packet_End,Packet_End.length);  
     System.out.println("packet_end index is:"+index_end);
     if(index_end==-1) continue;
     int recive_sum = (0xff & reciver_buffer[index_end-1])<<8;
     int check_sum=0;
     for(int i=0;i<recive_length-3;i++)
     check_sum+=(0xff & reciver_buffer[i])<<8;
     System.out.println("recive_sum is : "+ Integer.toHexString(recive_sum));
     System.out.println("check_sum is : "+ Integer.toHexString(check_sum));
     if((byte)recive_sum!=(byte)check_sum) continue;
     System.out.println("data packet is valid!");
     int packet_cmd = 0xff & reciver_buffer[2];
     int packet_cmd_reserved =  0xff & reciver_buffer[3];
     int recive_valid_length = ((0xff & reciver_buffer[7])<<8)+ (0xff & reciver_buffer[6]);
     int valid_data_length = 0;
             byte sum=0;
            
     switch (packet_cmd) {
    case 0x10:
    ccid = ((0xff & reciver_buffer[4])<<8)+(0xff & reciver_buffer[5]);
    System.out.println("ccid is : "+ccid);
    if (ccid==0x00) {
    //控制客户端登陆
    if(login_succed==false){
    //发登陆成功回应 
                valid_data_length = 0x07;
    byte send_longin_ack [] =  new byte[]{(byte) 0x4c,0x53,(byte)0xef,0x00,(byte)(ccid>>8),(byte)ccid,(byte)valid_data_length,(byte)(valid_data_length>>8),
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,sum,0x0d,0x0a};
    for(int i=0;i<send_longin_ack.length-3;i++)
    sum+=0xff & send_longin_ack[i];
    send_longin_ack[send_longin_ack.length-3]=(byte)sum;
    pw.write(send_longin_ack, 0, send_longin_ack.length);
    login_succed = true;
    socket.setSoTimeout(0);
    System.out.println("ecc id:"+ccid+" longin succeed!");
               }
    }
    else {
    //ecc登陆

               if(login_succed==false){
    //发登陆成功回应 
                //登陆成功,修改数据库状态 ccid
                valid_data_length = 0x07;
    byte send_longin_ack [] =  new byte[]{(byte) 0x4c,0x53,(byte)0xef,0x00,(byte)(ccid>>8),(byte)ccid,(byte)valid_data_length,(byte)(valid_data_length>>8),
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,sum,0x0d,0x0a};
    for(int i=0;i<send_longin_ack.length-3;i++)
    sum+=0xff & send_longin_ack[i];
    send_longin_ack[send_longin_ack.length-3]=(byte)sum;
    pw.write(send_longin_ack, 0, send_longin_ack.length);
    login_succed = true;
    System.out.println("ecc id:"+ccid+" longin succeed!");
    CcidHashSet.add(Integer.toHexString(ccid));
    SocketHashMap.put(Integer.toHexString(ccid), socket);
               }
    }

    break;
    case 0x11:
    //心跳包 
    //发心跳回应 
                if(login_succed==true){
                 valid_data_length = 0x00;
     byte send_heart_ack [] =  new byte[]{(byte) 0x4c,0x53,(byte)0xee,0x00,(byte)(ccid>>8),(byte)ccid,(byte)valid_data_length,(byte)(valid_data_length>>8),
             sum,0x0d,0x0a};
     for(int i=0;i<send_heart_ack.length-3;i++)
    sum+=0xff & send_heart_ack[i];
     send_heart_ack[send_heart_ack.length-3]=(byte)sum;
     pw.write(send_heart_ack, 0, send_heart_ack.length);
                }
    break;
    case 0x20:
    //查询数据回应 ,处理并存入数据库
                if (login_succed==true) {
    switch (packet_cmd_reserved) {
    case 0x00://正常响应
    System.out.println("recive_valid_length is "+ recive_valid_length);
     byte send_meter [] = new byte [recive_valid_length];
     for (int i = 0; i < send_meter.length; i++) {
    send_meter[i] = reciver_buffer[i+8];
    }
     boolean crc_check = ModbusCrc16.checkBuf(send_meter);
     System.out.println("crc check is "+crc_check);
     if (crc_check) {
    MeterDatas meter = new MeterDatas(send_meter, ccid);
    if (meter.MeterUpdate()) {
    //存到数据库或者直接传给需要客户端
    System.out.println("DIO is :"+(0xff & meter.DIO));
    System.out.println("Ua is :"+meter.Ua);
    System.out.println("Ub is :"+meter.Ub);
    System.out.println("Uc is :"+meter.Uc);
    System.out.println("HZ is :"+meter.Hz);
    }
    else {
    System.out.println("meter datas parse error!");
    }
    }
    break;
      

  7.   

    case 0x01://异常响应
    System.out.println("read meter error!");
    break;
    default:
    break;
    }
    }

    break;
    case 0xd0:
    String eccidString = Integer.toString(((0xff & reciver_buffer[8])<<8)+(0xff & reciver_buffer[9])); 
    System.out.println("eccid is "+ eccidString);
    sendSocket=SocketHashMap.get(eccidString);
    if (sendSocket!=null) {
    OutputStream sop = sendSocket.getOutputStream();
    System.out.println("sendSocket is exsitl!");
    valid_data_length = 0x0b;
        byte sum1=0;
        byte meterAddr =(byte) (0xff & reciver_buffer[10]);
        byte meterCmd = (byte)0x10;
        int regStartAddr =0x21;
        int regCount = 0x01;
        int crcValue=0x00;
        int eccid =Integer.parseInt(eccidString, 16);
        byte toggleButton=0;
        if ((0xff & reciver_buffer[11])==0x01) {
         toggleButton =(byte)0xf0;
    }
        byte send_meter [] = new byte []{meterAddr,meterCmd,(byte)(regStartAddr>>8),(byte)regStartAddr,(byte)(regCount>>8),(byte)regCount,0x02,toggleButton,0x00};
    ModbusCrc16 modbusCrc16 = new ModbusCrc16();
    modbusCrc16.update(send_meter, send_meter.length);
    crcValue=modbusCrc16.value;
    byte send_control [] =  new byte[]{(byte) 0x4c,0x53,(byte)0xdf,0x00,(byte)(eccid>>8),(byte)eccid,(byte)valid_data_length,(byte)(valid_data_length>>8),
    meterAddr,meterCmd,(byte)(regStartAddr>>8),(byte)regStartAddr,(byte)(regCount>>8),(byte)regCount,0x02,toggleButton,0x00,(byte)crcValue,(byte)(crcValue>>8),sum1,0x0d,0x0a};
    for(int i=0;i<send_control.length-3;i++)
    sum1+=0xff & send_control[i];
    send_control[send_control.length-3]=(byte)sum1;
    sop.write(send_control, 0, send_control.length);
    System.out.println("send control meter cmd finished!");
    sendSocket = null;
    }
    else {
    System.out.println("sendSocket is null!");
    }

    break;
    default:
    break;
    }
            }
            else
             break;
            }
    }catch (Exception e) {
    e.printStackTrace();
    }finally{
    try {
    if(socket != null) {
    login_succed=false;
    CcidHashSet.remove(Integer.toHexString(ccid));
    SocketHashMap.remove(Integer.toHexString(ccid));
    socket.shutdownInput();
    socket.shutdownOutput();
    br.close();
    pw.close();
    socket.close();
      //断开连接,修改数据库状态 ccid
    }
     System.out.println(socket.getInetAddress()+":"+socket.getPort()+" is closed.");
    } catch (Exception e2) {
    e2.printStackTrace();
    }

    }
    }


    }
    public static void main(String[] args)throws IOException {
    // TODO Auto-generated method stub

    new EchoServer().service();
     
    }
        

    }
      

  8.   

    学习了,这个SOCKET还是要把数据包的测试一下,跟协议进行对比一下。