先看两段代码
int 转换 byte
- (NSData *)makeSendData
{
Byte serviceByteData[1] = {};
serviceByteData[0] =(Byte)((self.head.service & 0x000000FF));
Byte groupByteData[1] = {};
groupByteData[0] =(Byte)((self.head.group & 0x000000FF));
Byte typeByteData[2] = {};
typeByteData[0] =(Byte)((self.head.type & 0x0000FF00)>>8);
typeByteData[1] =(Byte)((self.head.type & 0x000000FF));
Byte lengthByteData[4] = {};
lengthByteData[0] =(Byte)((self.head.bodyLength & 0xFF000000)>>24);
lengthByteData[1] =(Byte)((self.head.bodyLength & 0x00FF0000)>>16);
lengthByteData[2] =(Byte)((self.head.bodyLength & 0x0000FF00)>>8);
lengthByteData[3] =(Byte)((self.head.bodyLength & 0x000000FF));
Byte byte[] = {serviceByteData[0],groupByteData[0],typeByteData[0],typeByteData[1],lengthByteData[0],lengthByteData[1],lengthByteData[2],lengthByteData[3]};
NSData *temphead = [[NSData alloc]initWithBytes:byte length:8];
NSMutableData *m_data = [[NSMutableData alloc] init];
[m_data appendData:temphead];
GPBMessage *message = self.body;
[m_data appendData:message.data];
//不打印心跳
if (self.head.service == 1 && self.head.type == CMDType_CtrClientHeartbeat) {
// NSLog(@"++++++++++++++++++TCP发送心跳");
return m_data;
}
if (self.head.service == 2 && self.head.type == MessageTypeCode_MessageTypeSyncConn) {
return m_data;
}
if (self.head.service == CMDService_IM || self.head.service == CMDService_common) {
return m_data;
}
#if DEBUG
NSLog(@"TCP发送消息\nhead:%@, \nbody:%@",self.head,self.body);
#endif
return m_data;
}
byte 转int
- (BOOL)parseHeadWithData:(NSData *)data
{
if (data.length != 8) {
return NO;
}
Byte serviceLengthBytes[1];
[data getBytes:serviceLengthBytes range:NSMakeRange(0, 1)];
self.messageData.head.service = (int) ((serviceLengthBytes[0]&0xff));
Byte groupLengthBytes[1];
[data getBytes:groupLengthBytes range:NSMakeRange(1, 1)];
self.messageData.head.group = (int) ((groupLengthBytes[0]&0xff));
Byte typeLengthBytes[2];
[data getBytes:typeLengthBytes range:NSMakeRange(2, 2)];
self.messageData.head.type = ((typeLengthBytes[0]&0xff)| ((typeLengthBytes[1] << 8)&0xff00));
Byte bodyLengthBytes[4];
[data getBytes:bodyLengthBytes range:NSMakeRange(4, 4)];
self.messageData.head.bodyLength = ((bodyLengthBytes[0]&0xff) | ((bodyLengthBytes[1] << 8)&0xff00) | ((bodyLengthBytes[2] << 16)&0xff0000) | ((bodyLengthBytes[3] << 24)&0xff000000));
if (checkCPUendian() == 1) {
self.messageData.head.type = ntohs(self.messageData.head.type);//小端转大端
}
if (checkCPUendian() == 1) {
self.messageData.head.bodyLength = ntohl(self.messageData.head.bodyLength);//小端转大端
}
return YES;
}
因项目里用到socket ,需要按位去读取报文信息,报头总共8个字节,其中
- server 占一个字节
- group 占一个字节
- type 占两个字节
- bodyLength 占四个字节
以上代码就是是约定的报头解析和组装部分。
组装
占用一个字段的就先略过了,不需要移位,直接使用即可。
type 字段占用两个字节
typeByteData[0] =(Byte)((self.head.type & 0x0000FF00)>>8);
typeByteData[1] =(Byte)((self.head.type & 0x000000FF));
一个字节占8位二进制,相当于两位16进制,所以type占两个字节的话,那么最大值就是 0x0000FFFF。
其中第一个字节typeByteData[0],和0x0000FF00 按位与 就相当于只保留前两位16进制的值,其它全清零,然后再右移8位就等于把右侧零全部消除,然后就得到了type字段代表的16进制的高位。
其余逻辑类似。
解析
Byte typeLengthBytes[2];
[data getBytes:typeLengthBytes range:NSMakeRange(2, 2)];
self.messageData.head.type = ((typeLengthBytes[0]&0xff)| ((typeLengthBytes[1] << 8)&0xff00));
其中 (typeLengthBytes[0]&0xff) 部分 ,因为typeLengthBytes[0]就代表低位,所以 &0xff基本也没什么意义,关键的typeLengthBytes[1] << 8 就等于将高位的值左移8位,再将右侧的8位清零, 此处的&0xff00 其实也没什么意义,所以可以简写为
self.messageData.head.type = ((typeLengthBytes[0])| (typeLengthBytes[1] << 8));
中间的|,按位或,意义等于将两位拼接,
比如 typeLengthBytes[1] = 1111000100000000, typeLengthBytes[0] = 0000000011101010.
拼接后就等于 1111000111101010,此时的值就代表两个字节的type字段。
其余逻辑类似。
大端小端
首先大小端的定义是啥?为什么会有大小端之分?
一串二进制流,最终要对应到计算机的内存中去计算,那么赋值时是按内存的从低到高,还是从高到低就有不一样的实现,本无性能优劣之分,只是两种实现而已
借两张图
![](https://img.haomeiwen.com/i1597685/ea47c55ca1d5b3f2.jpg)
![](https://img.haomeiwen.com/i1597685/f83f76ee7cc956ae.jpg)
大小端判断
int checkCPU()
{
union w
{
int a;//在ios中,4 Byte
char b;//在ios中,1 Byte
} c;
c.a = 1;
return(c.b ==1);//如果c.b == 1,表示第一位是0x01,那就是小端,如果返回0,就是大端
}
其原理主要使用union 类型来判断,其中union类型叫做共用体,一般用于编译期的内存优化,特性就是内部数据共享一个内存地址。所以如果给c.a赋值为1,那么去读b的值得时候,如果可以读到刚才设置的1 ,考虑a和b占用的字节数不一样,那么说明这个1被保存在了低位(参考上图1),那就是小端模式(),反之,那就是大端模式。
iOS中判断大小端的标准写法
if (NSHostByteOrder() == NS_LittleEndian) {
NSLog(@"LittleEndian");
}
else if(NSHostByteOrder() == NS_BigEndian){
NSLog(@"BigEndian");
}
else {
NSLog(@"Unknow");
}
因为服务端的默认为大端模式,所以iOS的小端需要稍微转换下,函数为:
ntohs(x)//两字节专用
ntohl(x) //四字节专用
完。
网友评论