关于socket通信的问题

cdkx945 2012-06-19 06:08:15
目前在做一个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的数组,然后一个一个从里面取出来判断
包头和包尾暂时已经搞定了····
但剩下的一些还没想好应该怎么做,求大神帮助,小弟才工作,还在试用期,不想丢工作啊!
谢谢各位了!
...全文
312 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
cdkx945 2012-07-01
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

提个思路:
1.一个接受线程,接受到数据之后就放到一个队列里面
2.有一个辅助线程这个线程就在刚才的队列里面找数据帧
找数据帧的过程可以定义成一个状态机,这个状态机有三种状态,找到帧头,空闲状态,找到帧(发现了帧头和帧尾)
具体操作如下:
2.1 刚开始讲状态机设置为空闲状态,然后如果在队列里面发现了帧头,转到找到帧头状态,否则的话将不是帧头的数据出队,维持状态为空闲状态
2.2 如……
[/Quote]我现在快做好就是客户端对服务端发数据包,服务端的相应差不多快做好了。那我应该如何写客户端主动发送的那些数据包呢?
asianboy1006 2012-07-01
  • 打赏
  • 举报
回复
学习了,这个SOCKET还是要把数据包的测试一下,跟协议进行对比一下。
cdkx945 2012-06-29
  • 打赏
  • 举报
回复
上面这个是第一个类
cdkx945 2012-06-29
  • 打赏
  • 举报
回复
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();

}


}
cdkx945 2012-06-29
  • 打赏
  • 举报
回复
我把代码贴出来 大家帮忙看看···
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;
xlhb 2012-06-27
  • 打赏
  • 举报
回复
思路,
1. 将二进制解析为对象,
2. 对对象进行sum校验,
3. 分发消息.(关机,开机,其他)
shihp 2012-06-27
  • 打赏
  • 举报
回复
上网上搜搜,这种例子很多的,qq 49584702
蓝翔技校码农 2012-06-26
  • 打赏
  • 举报
回复
提个思路:
1.一个接受线程,接受到数据之后就放到一个队列里面
2.有一个辅助线程这个线程就在刚才的队列里面找数据帧
找数据帧的过程可以定义成一个状态机,这个状态机有三种状态,找到帧头,空闲状态,找到帧(发现了帧头和帧尾)
具体操作如下:
2.1 刚开始讲状态机设置为空闲状态,然后如果在队列里面发现了帧头,转到找到帧头状态,否则的话将不是帧头的数据出队,维持状态为空闲状态
2.2 如果找到帧头,没有找到帧尾,就继续找,直到找到为止,找到之后,转到找到帧状态,这时候将这段数据复制出去,然后转到空闲状态
3.对找到的数据帧进行校验(帧格式你自己肯定知道的),校验错误,丢弃该帧,否则将帧中有用数据解析到对象里面

我不清楚的你的数据格式,可以的话给你定个帧格式。
希望对你有帮助
cdkx945 2012-06-26
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 shihp 的回复:]

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


我现在写了一些方法来判断这个,但是依旧是有问题的。能留个QQ不? 我直接QQ上问···
cdkx945 2012-06-26
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

如果你把问题提的更具体一些的话,也许能好些。
[/Quote]


能加QQ聊么?这样方便一些!
shihp 2012-06-26
  • 打赏
  • 举报
回复
我觉得socket通信,首先要解决,收到的数据是不是完整的,如果是完整的,那就不存在那么多问题了,我做的socket通信,用到的数据包,都是包头的前几个byte值表示这个数据包的长度,程序在收包时按这个长度进行读取。你要先确保你收到的数据包是完整的,这是我的建议,你参考下
anod 2012-06-26
  • 打赏
  • 举报
回复
如果你把问题提的更具体一些的话,也许能好些。
cdkx945 2012-06-25
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
目前在做一个c/s的项目·····
做socket通信模块 要传十六进制的数据包····
就是那种上位机变成
例如这样的数据包 0x4c 0x53 0x10 0x00 0x00 0x01 0x02 0x00 0x01 0x00 sum 0x0d 0x0a


这其中 0x4c 0x53是包头 0x0d 0x0a是包尾
这2个是固定不变的!
紧跟着包头的0x……
[/Quote]
是这样的!我做的这个必须用十六进制··· 大致的格式如上所述
cdkx945 2012-06-25
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

我提几个建议:
1、基础结构上,需要有以下一些东西:
a、负责接受数据的,比如一个线程。接受后的数据放在一个byte缓冲里。用队列。
b、拆包的。这里面可以再分成两个步骤:首先按照包头包尾拆包。需要主意的是,如果你发现收到了不完整的包,那么需要把已经从队列中取出的数据反向压回去。拆包后,可以验证以下校验和。如果不对的话,就可以直接扔了。第二步,拆包后,再解析。也就是把拆包结果转……
[/Quote]
不好意思,我回家了几天,一直没网!
是这样的,我在这之前就已经在这么做了,但是具体做的时候,还是遇到了相当多的问题。比如你上面提到的校验码的问题,我大致的写出了方法,但是现在做的有问题!还望多多帮助!
anod 2012-06-21
  • 打赏
  • 举报
回复
我提几个建议:
1、基础结构上,需要有以下一些东西:
a、负责接受数据的,比如一个线程。接受后的数据放在一个byte缓冲里。用队列。
b、拆包的。这里面可以再分成两个步骤:首先按照包头包尾拆包。需要主意的是,如果你发现收到了不完整的包,那么需要把已经从队列中取出的数据反向压回去。拆包后,可以验证以下校验和。如果不对的话,就可以直接扔了。第二步,拆包后,再解析。也就是把拆包结果转化为数据对象,比如消息对象。这时,你已经知道消息类型和其中的数据了。拆包后的数据可以放在一个缓冲里,比如list,也可以直接处理。
c、处理消息的代码。可以为每一种消息创建一个消息处理类。处理后,如果有返回消息要封装成对象,并压入发送缓冲。
d、发送消息的代码,可能是一个线程。从发送队列中取出需要发送的消息并转化为byte数组发出去。

需要小心的问题:
1、消息结构,如果能用定长最好,这样会减少解析复杂度。
2、大小端的问题要约定好。
3、需要自己搞一些基础件,比如byte数组转换为int,int转换为byte数组之类的。这些基础件一定要经过充分测试,否则,后果是灾难性的。
4、操作容器类要小心迭代过程中不能修改容器。
大概就是这样,不难。
FFF9527 2012-06-19
  • 打赏
  • 举报
回复
中间的结构不太清楚。

最好拿一个具体的二进制数据包,讲一下格式.

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

62,623

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧