c 程序java_java程序和C/C 程序的通讯...

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

该问题起源于笔者设计的基于Web的远程测控系统。它的基本原理是:服务器端运行一VC编制的服务器程序,客户端使用Java

applet;VC服务器程序接收到Java

applet发送的命令后,采集各种信息,并将所有数据发向applet,实现了基于Web的远程温度、加速度的实时监控。

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

59579_10635844_1.gif

59579_10635844_2.gif

基于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)

{

}

}

}

59579_10635844_1.gif

59579_10635844_2.gif

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

{

ch1[i]=input.readShort();

if(ch==2)

ch2[i]=input.readShort();

}

if(bit==8)

for(i=0;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];

59579_10635844_1.gif

59579_10635844_2.gif

根据前面的分析,笔者设计了一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

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

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

{

...见前面

}

59579_10635844_4.jpg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值