当前位置: 首页 > news >正文

通讯中的字节网络顺序和字节主机顺序

C/C++ 写网络程序的时候,往往会遇到字节的网络顺序和主机顺序的问题。
其实数据的顺序是由 cpu 决定的 , 与操作系统无关。
Intel x86 结构下 ,short 型数 0x1234 表示为 34 12,int 型数 0x12345678 表示为 78 56 34 12
IBM power PC 结构下 ,short 型数 0x1234 表示为 12 34,int 型数 0x12345678 表示为 12 34 56 78
由于这个原因不同的机器之间无法通信 , 所以要转换成一种约定的数序 , 也就是网络字节顺序 , 其实就是如同 power pc 那样的顺序
PC 开发中有 ntohl htonl 函数可以用来进行网络字节和主机字节的转换,但是 Symbian 开发中没有这两个函数,那就要自己写接口来进行转换了。
下面是两个进行转换的接口:
// 主机顺序转换成网络顺序 网络顺序转换成主机顺序
inline unsigned long HTONL(unsigned long h)
{
return (h>>24)+((h>>16)<<8)+((h>>8)<<16)+(h<<24);
}
// 主机顺序转换成网络顺序 网络顺序转换成主机顺序
inline unsigned short HTONS(unsigned short h)
{
return (h>>8)+(h<<8);
}
这些问题在 Java 做为 Server 端, Symbian 做为 Client 端时表现的更为明显,因为 Java 中的通讯传输的都是网络字节。到了 Symbian 端要转换成主机字节。
比如你要发送一个结构
structtest{
shorta;
int b;
longc;
floatd;
double f;
};
testst;
char*p = (char*)&st;//
看看 p 中的字节顺序(就是发送的字节顺序)

java
端你相应写些函数进行转换就行了。
举一个例子:
//
c 对应的 ntohl 函数
public static long ntohl(long in){
long out = 0;
out = (in&0xff)<<24;
out |= (in&0xff00)<<8;
out |= (in&0xff0000)>>8;
out |= (in&0xff000000)>>24;
return out;
}
下面再转几篇不错的文章:
原文地址:http://blog.csdn.net/kingfish/archive/2005/03/29/333635.aspx

近几天看到csdn上问c/c++和java通信的问题比较多,特别是c特有的数据结构(如struct)。

特地根据网友的一个问题举个例子,希望对初学者有所帮助。

原问题见:http://community.csdn.net/Expert/topic/3886/3886989.xml?temp=.3527033

这类问题通常是为了利用原有Server或者Server不能做修改(通常是c/c++)造成。

比如Server端只接收一个结构Employee,定义如下:

struct UserInfo {
char UserName[20];
int UserId;
};
struct Employee {
UserInfo user;
float salary;
};
当然也可以定义为

struct Employee {
char name[20];
int id;
float salary;
};

java client 测试源码(为说明问题,假设struct字节对齐,sizeof(Employee)=28)

import java.net.*;

/*
* 与C语言通信(java做Client,c/c++做Server,传送一个结构)
* @author kingfish
* @version 1.0
*/
class Employee {
private byte[] buf = new byte[28]; //为说明问题,定死大小,事件中可以灵活处理

/*
* 将int转为低字节在前,高字节在后的byte数组
*/
private static byte[] toLH(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}

/*
* 将float转为低字节在前,高字节在后的byte数组
*/
private static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}

/*
* 构造并转换
*/
public Employee(String name, int id, float salary) {
byte[] temp = name.getBytes();
System.arraycopy(temp, 0, buf, 0, temp.length);

temp = toLH(id);
System.arraycopy(temp, 0, buf, 20, temp.length);

temp = toLH(salary);
System.arraycopy(temp, 0, buf, 24, temp.length);
}

/**
* 返回要发送的数组
*/
public byte[] getBuf() {
return buf;
}

/**
* 发送测试
*/
public static void main(String[] args) {
try {
Socket sock = new Socket("127.0.0.1", 8888);
sock.getOutputStream().write(new Employee("kingfish", 123456789, 8888.99f).
getBuf());
sock.close();
}
catch (Exception e) {
e.printStackTrace();
}

} //end

当然,也可以利用writeInt,writeFloat方法发送,但字节顺序需要改为低在前。
这个问题稍后在讨论。

第一部分请见http://blog.csdn.net/kingfish/archive/2005/03/29/333635.aspx

本部分提出另外一种做法, 供参考。


import java.net.*;
import java.io.*;

/**
* 与C语言通信(java做Client,c/c++做Server,传送一个结构)
* @author kingfish
* @version 1.0
*/
public class Employee2 {
private String name;
private int id;
private float salary;

/**
* 将int转为低字节在前,高字节在后的int
*/
private static int toLH(int in) {
int out = 0;
out = (in & 0xff) << 24;
out |= (in & 0xff00) << 8;
out |= (in & 0xff0000) >> 8;
out |= (in & 0xff000000) >> 24;
return out;
}

/**
* 将float转为低字节在前,高字节在后的int
*/
private static int toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}

/**
* 构造并转换
*/
public Employee2(String name, int id, float salary) {
this.name = name;
this.id = id;
this.salary = salary;
}

/**
* 取得名字,定长byte数组
*/
public byte[] getName() {
byte[] b = new byte[20];
System.arraycopy(name.getBytes(), 0, b, 0, name.getBytes().length);
return b;
}

/**
* 取得编号(低字节在前)
*/
public int getId() {
return toLH(id);
}

/**
* 取得工资(低字节在前)
*/
public int getSalary() {
return toLH(salary);
}

/**
* 发送测试
*/
public static void main(String[] args) {
try {
Employee2 p = new Employee2("kingfish", 123456789, 8888.99f);

Socket sock = new Socket("127.0.0.1", 8888);
DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
dos.write(p.getName());
dos.writeInt(p.getId());
dos.writeInt(p.getSalary());

sock.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
} //end

相关文章:

  • python tableau自动化导出_使用 Python 导出 Tableau 自定义形状 (Extracting Tableau Custom Shapes Using Python)...
  • tableau三轴该怎么做_在视图中为多个度量添加轴
  • 投资者的七个等级
  • python正则表达读取word_python 正则表达
  • python中土耳其编码范围_Python-编码这趟浑水
  • 做聪明的人很容易,但做善良的人很难
  • webis个人主页设计_个人网页(个人主页)设计论文
  • [个人] 确立了新的研究方向
  • java读书心得_范文精选-读书心得体会-java夜未眠读书心得
  • 经典导航菜单脚本收藏
  • axure 导入元件库显示不出白框_如何用Axure画出Web后台产品的面包屑组件
  • Oracle常用命令
  • echarts 使用热力图 如何能做到在每一个热力点的方格内显示自己需要的数据_3种高级分析型图表,直观解读数据,手把手教你制作...
  • 什么叫h5项目_揭秘使用H5自适应建设网站有哪些优势
  • Windows Mobile 5.0 认知篇
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 【前端学习】-粗谈选择器
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • avalon2.2的VM生成过程
  • classpath对获取配置文件的影响
  • Cumulo 的 ClojureScript 模块已经成型
  • exif信息对照
  • gitlab-ci配置详解(一)
  • HashMap剖析之内部结构
  • Mac转Windows的拯救指南
  • PHP 7 修改了什么呢 -- 2
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 今年的LC3大会没了?
  • 两列自适应布局方案整理
  • 前端代码风格自动化系列(二)之Commitlint
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 一些css基础学习笔记
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • PostgreSQL之连接数修改
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ![CDATA[ ]] 是什么东东
  • #1015 : KMP算法
  • #Linux(make工具和makefile文件以及makefile语法)
  • (3)STL算法之搜索
  • (4)logging(日志模块)
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (二)Eureka服务搭建,服务注册,服务发现
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)Sublime Text3配置Lua运行环境
  • (转)详解PHP处理密码的几种方式
  • .NET Core WebAPI中封装Swagger配置
  • .Net 代码性能 - (1)
  • .NET 依赖注入和配置系统
  • .netcore如何运行环境安装到Linux服务器