`
celebration
  • 浏览: 34992 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java和C/C++程序实时通讯数据移植问题的研究

阅读更多
摘要:本文研究了数据存储格式中大尾小尾问题,根据此原理解决了Java程序和C/C++通讯及读取服务器端文件时的数据移植问题。

问题起源

该问题起源于笔者设计的基于Web的远程测控系统。它的基本原理是:服务器端运行一VC编制的服务器程序,客户端使用Java applet;VC服务器程序接收到Java applet发送的命令后,采集各种信息,并将所有数据发向applet,实现了基于Web的远程温度、加速度的实时监控。

VC程序和Applet之间的通讯方式采用了基于TCP/IP协议的socket通讯,笔者不准备在socket的通讯本身进行过多的讲述,而将重点研究实时通讯中涉及到的数据移植问题。

 




回页首


数据移植的原因及其解决

基于Web的测试软件是由C++数据采集服务器程序和客户端Java显示程序两部分构成,前者用C++,后者Java语言,存在数据移植问题。因为在计算机系统中,当包含数字的二进制文件从一个结构移到另一结构时,就出现大尾小尾问题。不同CPU在多字节数(如四字节int)存储时有两种方法,一种方法叫小尾(little_endian),数据的低字节被放置在连续存储区的首位,另一种方法叫大尾(big_endian),数据的高字节被放置在连续存储区的首位。Intel 80×86家族处理器是最后一个仍然坚持小尾的主要结构。所有其他的CPU结构(Motorola 680×0和所有RISC芯片)或者是纯粹的大尾或者是既适应大尾也适应小尾,大尾被认为是更符合逻辑的方法)。当数字由小尾处理器写入文件然后又由大尾处理器读取(或者倒过来)时,数字就会被搞乱(除了0和-1)。

运用C++或C语言,数据在文件中的存储形式是与处理器相关的,这使得简单的数据文件的移植成为一个大问题。而Java作为平台独立语言,所有的数据都是以大尾形式存储到文件中,Java语言本身产生的数据文件无移植问题。但是它在与C/ C++通讯时还应注意,

举个例子:float型数据1.5在VC程序和Java程序中的表示如下:

数值 在c++或c程序中的字节表示 在java程序中的字节表示
1.5 00111111 11000000 00000000 00000000 00000000 00000000 11000000 00111111
byte[] data=new byte[4]; 
length=in.read(data,0,data.length);//将服务器发送的字节流读入并存入data数组
DataInputStream huin = new DataInputStream(new ByteArrayInputStream(data));
float f = huin.readFloat(); //将1.5读出

 

但是,f并不等于1.5,必须将data接收到的字节流进行数据移植(小尾排序方式改为大尾排序),data[0]的值和data[3]值互换,data[1]的值和data[2]的值互换。

byte[] data=new byte[4]; 
length=in.read(data,0,data.length);//将服务器发送的字节流读入并存入data数组
byte b1;
b1=data[0];
data[0]=data[3];
data[3]=b1;
b1=data[1];
data[1]=data[2];
data[2]=b1;
DataInputStream huin = new DataInputStream(new ByteArrayInputStream(data));
float f = huin.readFloat(); //将1.5读出

 

这样,得到了正确的结果。

笔者针对此问题设计了一个数据移植类WindowsStream,它的作用是把C/C++格式的数据转换成Java格式数据,使得Java程序可以读取 C/C++发送的数据和文件。该类将各种数据类型读入缓冲中(逐个字节读),然后在缓冲区中改变字节的排序方式,其源程序如下:

class WindowStream extends FilterInputStream
{
public WindowStream(InputStream in)
{
super(in);
}
public final byte readByte() throws IOException
{
int a=in.read();
return (byte)(a);
}
public final short readShort() throws IOException
{
InputStream in=this.in;
int a1=in.read();
int a2=in.read();
return (short)((a2<<8)+a1);
}
public final int readInt() throws IOException
{
InputStream in=this.in;
int a1=in.read();
int a2=in.read();
int a3=in.read();
int a4=in.read();
return ((a4<<24)+(a3<<16)+(a2<<8)+a1);
}
public final long readLong() throws IOException
{
InputStream in=this.in;
return ((long)readInt()<<32)+(readInt()&0xFFFFFFFFL);
}
public final float readFloat() throws IOException
{
return Float.intBitsToFloat(readInt());
}
public final double readDouble() throws IOException
{
return Double.longBitsToDouble(readLong());
}
}

 

配合本Java客户程序(其源程序见最后)的UDP服务器程序(服务端口8888)(该程序可以在 ftp//202.114.6.107/incoming处下载或E_mailTome:windgf@263.net),在接收到客户端命令(此处设为 “DAT”)后,将向客户端返回2K byte型数据,Java客户端使用UdpData的read方法接收。read方法中host表示运行UDP服务器程序的IP地址,buffer用于存储接收到的数据,ch1用于存储转换后的short型数据,下面这个程序片断简要演示了UdpData的用法。

...
host=getCodeBase().getHost();
UdpData udph1=new UdpData();
...
udp1.read(host,buffer,x1);
ch=1;
fre=11025;
len=1024;
bit=16;
...
UdpData的源程序:
class UdpData
{
public UdpData(){}
public void read(String host,byte[] buffer,short[] ch1)
{
int i,len=0;
InputStream in;
OutputStream out;
Socket server;
try
{
String str="DAT";
byte[] order=str.getBytes();
server=new Socket(host,8888,false);
in=server.getInputStream();
out=server.getOutputStream();
out.write(order,0,order.length);
out.flush();
len=in.read(buffer);
server.close();
}
catch(Exception e)
{
len=0;
}
try
{
WindowStream input=new WindowStream(new ByteArrayInputStream(buffer));
for(i=0;i<1024;i++)
ch1[i]=input.readShort();
}
catch(Exception e)
{
}
}
}





回页首


服务器端.wav文件的读取

Java和C++程序在写文件时也使用了不同的数据格式,所以,Java程序不能从C++程序创建的文件直接读取二进制数据。在读取服务器端的.wav文件时,同样涉及到数据移植的问题,.wav的文件结构具有如下:

char r[4];
long int fs;
char w[8];
long int hs;
short int p,ch;
long int hz,bhz;
short int b,bit;
char d[4];
long int ds;
char *wave;

 

ch:记录通道数,hz:采样频率,bit:模数转换的位数,ds:文件的长度,wave:指向数据的指针。此处假定long int在C/C++中是四个字节,而在Java中为8个字节。

以下是类WavFile源文件,其read方法用于读取.wav文件,location标识.wav文件的URL,buffer是用于存储原始数据的缓存,ch1和ch2分别用于存储左右两通道的数据,

class WavFile
{
public WavFile(){}
public void read(URL location,byte[] buffer,short[] ch1,short[] ch2,int 
max,int[] par)
{
try
{
URLConnection con=location.openConnection();
DataInputStream in=new DataInputStream(con.getInputStream());
in.read(buffer);
in.close();
}
catch(Exception e){}
int i,m,bit=0,ch=0,fre=0,len=0;
try
{
WindowStream input=new WindowStream(new ByteArrayInputStream(buffer));
input.readLong();
input.readLong();
input.readInt();
input.readShort();
ch=input.readShort();
fre=input.readInt();
input.readInt();
input.readShort();
bit=input.readShort();
input.readInt();
len=input.readInt()*8/ch/bit;
if(len>max)len=max;
if(bit==16)
for(i=0;i<len;i++)
{
ch1[i]=input.readShort();
if(ch==2)
ch2[i]=input.readShort();
}
if(bit==8)
for(i=0;i<len;i++)
{
ch1[i]=(short)(input.readByte()-128);
if(ch==2)
ch2[i]=(short)(input.readByte()-128);
}
}
catch(Exception e){}
par[0]=ch;
par[1]=fre;
par[2]=len;
par[3]=bit;
}
}

 

下面的程序片断演示了如何在java程序中使用WavFile读取.wav文件

int ch=0,len=0,fre=0,bit=0;
short x1[]=new short[16385];
short x2[]=new short[16385];
byte buffer[]=new byte[64540];
int par[]=new int[5];
name=”ding.wav”;
url1=new URL(getDocumentBase(),name);
WavFile h1=new WavFile();
...
h1.read(url,buffer,x1,x2,16384,par);
ch=par[0];
fre=par[1];
len=par[2];
bit=par[3];





回页首


Java演示程序

根据前面的分析,笔者设计了一Java applet程序,成功读取服务器端.wav文件和接收UDP服务器程序发送的数据,并在applet的面版上进行显示。

import java.awt.*;
import java.applet.*;
import java.net.*;
import java.util.*;
import java.io.*;
public class read_wav_udp extends Applet
{
TextField tex0;
Button but1,but2,but3;
WavFile h1=new WavFile();
UdpData udph1=new UdpData();
int ch=0,len=0,fre=0,bit=0;
double t=0,a1=0,a2=0;
short x1[]=new short[16385];
short x2[]=new short[16385];
byte buffer[]=new byte[64540];
int par[]=new int[5];
public read_wav_udp(){}
public void init()
{
Font NewFnt=new Font("Roman",Font.PLAIN,12);
this.setFont(NewFnt);
resize(540,300);
setLayout(null);
udph1=new UdpData();
tex0=new TextField("");
add(tex0);
tex0.reshape(28,10,500,20);
but1=new Button("Ding");
add(but1);
but1.reshape(130,260,60,20);
but2=new Button("Chord");
add(but2);
but2.reshape(230,260,60,20);
but3=new Button("UDP");
add(but3);
but3.reshape(330,260,60,20);
data("ding.wav");
}
public boolean action(Event evt,Object o)
{
if(evt.target==but1)
data("ding.wav");
if(evt.target==but2)
data("chord.wav");
if(evt.target==but3)
data1();
repaint();
return true;
}
public void data(String name)
{
URL url1;
try
{
url1=new URL(getDocumentBase(),name);
}
catch(Exception e)
{
url1=getDocumentBase();
}
h1.read(url1,buffer,x1,x2,16384,par);
ch=par[0];
fre=par[1];
len=par[2];
bit=par[3];
}
public void data1()
{
String host;
host=getCodeBase().getHost();
udph1.read(host,buffer,x1);
ch=1;
fre=11025;
len=1024;
bit=16;
}
public void paint(Graphics g)
{
drawwave(g);
tex0.setText("CH="+ch+",Fs="+fre+",Len="+len+",Bit="+bit);
}
public void drawwave(Graphics g)
{
int i,xx1,xx2,yy1,yy2;
double ff=1,sa,la,k,mm;
g.setColor(Color.lightGray);
g.fillRect(0,0,600,400);
g.setColor(Color.black);
g.drawRect(28,40,500,200);
g.drawString("A",14,50);
g.drawString("-A",8,240);
g.drawString("0",14,145);
g.drawString("0",30,255);
g.drawString("T",525,255);
t=500.0/fre;
if(ch==0)return;
sa=la=x1[1];
for(i=1;i<500;i++)
{
if(sa>x1[i])
sa=x1[i];
if(la<x1[i])
la=x1[i];
}
a1=Math.max(Math.abs(sa),Math.abs(la));
k=1.2*a1;
ff=100/k;
g.setColor(Color.red);
for(i=1;i<500;i++)
{
xx1=28+i;
yy1=(int)(140-x1[i]*ff);
xx2=29+i;
yy2=(int)(140-x1[i+1]*ff);
g.drawLine(xx1,yy1,xx2,yy2);
}
if(ch==1)
return;
sa=la=x2[1];
for(i=1;i<500;i++)
{
if(sa>x2[i])
sa=x2[i];
if(la<x2[i])
la=x2[i];
}
a2=Math.max(Math.abs(sa),Math.abs(la));
k=1.2*a2;
ff=100.0/k;
g.setColor(Color.blue);
for(i=i;i<500;i++)
{
xx1=28+i;
yy1=(int)(140-x2[i]*ff);
xx2=29+i;
yy2=(int)(140-x2[i+1]*ff);
g.drawLine(xx1,yy1,xx2,yy2);
} 
}
}
class WindowStream extends FilterInputStream
{
...见前面
}
class WavFile
{
...见前面
}
class UdpData
{
...见前面
}





关于作者

 

高峰:华中科技大学研究生,同时就职于武汉思旦信息技术有限公司,主要从事信息、网络安全方面的研究和开发。其参与的《工程测试CAI教室》获得 '99 Sun/CERNET Java现代远程教学课件制作大赛并列第一名。

分享到:
评论

相关推荐

    java版的飞鸽程序

    Java版的飞鸽程序是一种基于Java编程语言实现的即时通讯软件,它打破了传统飞鸽程序主要由C/C++编写的常规。Java作为一种跨平台、面向对象的语言,以其“一次编写,到处运行”的特性,为飞鸽程序提供了更广泛的兼容...

    关于C++ :1.入门知识

    C++因其高效、灵活、功能丰富、表达力强和高可移植性等特点,在系统软件和应用软件开发中被广泛采用。 对于初学者而言,学习C/C++编程可以采取多种途径。例如,可使用Visual Studio 2015这一专业的编程开发平台。...

    c++开发手册

    通过以上概述可以看出,这些 C++ 开源框架和开发工具覆盖了从基础的数据结构和算法库到 GUI 库和网络编程库等多个方面,极大地丰富了 C++ 开发者的工具箱,使得他们能够在各种应用场景下更加高效地完成任务。

    android-pcsc:Android PCSC 智能卡移植(USB 读卡器)

    本篇将深入探讨如何将PC/SC移植到Android系统,以及如何通过JNI接口实现Java和C语言的交互,以便利用USB读卡器进行智能卡操作。 **一、PC/SC简介** PC/SC全称为个人计算机/智能卡,它定义了一套标准接口,使得不同...

    Mars是微信开发的跨平台网络组件。_C++_C_下载.zip

    Mars是微信团队开发的一款强大的跨平台网络通信组件,它主要使用C++和C语言编写,为开发者提供了高效、稳定且易用的网络编程接口。这个组件的设计目标是为了应对大规模分布式系统中的网络通信挑战,特别是在移动设备...

    jsr80 java 访问 usb

    目前,大多数一般用途的操作系统都提供了对 USB 设备的支持,并且用 C 或者 C++ 可以相对容易地开发访问这些外设的应用程序。不过,Java 编程语言在设计上对硬件访问提供的支持很少,所以编写与 USB 设备交互的应用...

    优秀生传授学习Android的学习步骤

    - **ARMLinux中的GNUC难点和重点**:特别强调在ARMLinux平台上使用GNUC时需要注意的问题。 #### 第三阶段:Android Java编程训练和工具 Java是Android应用程序开发的主要语言。此阶段将深入学习Java语言的基础知识...

    MySQL中文参考手册.chm

    &lt;br/&gt;11 MySQL 基准套件 &lt;br/&gt;12 MySQL 实用程序&lt;br/&gt;12.1 各种 MySQL 程序概述 &lt;br/&gt;12.2 管理一个 MySQL 服务器 &lt;br/&gt;12.3 从 MySQL 数据库和表中倒出(dump)结构和数据 &lt;br/&gt;12.4 从文本文件导入数据 &lt;br/&gt;12.5 ...

    嵌入式软件开发基础-PPT课件.ppt

    6. **C语言程序的结构**:C语言目标文件通常包含代码段(存储执行代码)、只读数据段(存储常量)和读写数据段(存储全局变量和动态分配内存)。程序执行时,这些段会被加载到内存的相应区域。 在实际开发中,理解...

    华为通用referenc-ril

    5. **源代码结构**:通常,RIL的源代码包括Java代码(用户空间的RIL守护进程)和C/C++代码(内核空间的驱动)。Java部分主要处理与Android系统的交互,而C/C++部分则与硬件通信。 通过研究huaweigeneric-ril,...

    超级有影响力霸气的Java面试题大全文档

    引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...

    ARM应用系统开发详解

    - **掌握ARM汇编语言和C/C++编程**,了解Thumb指令集,提高代码的运行效率和移植性。 - **熟悉S3C4510B的数据手册**,理解其内部结构和外设接口,合理规划系统资源分配。 - **考虑电源管理策略**,充分利用ARM7...

    SOCKET编程详解(轻松学网络编程)

    - C/S(Client/Server)模型是Socket编程的基础,服务器程序创建Socket并监听特定端口,客户端请求连接到服务器,一旦连接建立,双方就可以通过Socket进行数据交换。 3. **创建Socket** - 在C++或Java等编程语言...

    常用的嵌入式数据库比较

    3. **高度可移植性:**Berkeley DB具有轻便灵活的特点,能够在几乎所有的UNIX和Linux系统及其变种系统、Windows操作系统以及多种嵌入式实时操作系统下运行。它的轻量级特性让终端用户在使用过程中几乎察觉不到数据库...

    青岛朗讯笔试题

    - II) C和C++的可移植性主要在源代码级,而Java支持从源代码到字节码的可移植性,因为Java虚拟机(JVM)可在多种平台上运行。 总的来说,青岛朗讯的笔试题涵盖了IT知识的多个方面,包括数学逻辑、算法实现、计算机...

    Socket SOAP 中间件

    - **编程模型**:提供了丰富的API和工具,支持C/C++等多种编程语言,便于开发者快速构建复杂的应用逻辑。 #### 四、SOAP协议 SOAP(Simple Object Access Protocol,简单对象访问协议)是一种轻量级的协议,用于在...

    MySQL中文参考手册

    # 7.3.6.1 问题和日期类型 # 7.3.6.2 DATETIME,DATE和TIMESTAMP类型 # 7.3.6.3 TIME类型 # 7.3.6.4 YEAR类型 + 7.3.7 字符串类型 # 7.3.7.1 CHAR和VARCHAR类型 # 7.3.7.2 BLOB和TEXT类型 # 7.3.7.3 ENUM类型...

Global site tag (gtag.js) - Google Analytics