在线等待:: java与C语言socket通讯,C语言的结构体我怎么接收? up有分
如题, 我要和C语言程序作socket通讯,但C语言程序中的socket发送接收都用了结构体,而java中没有结构体的概念,我该怎么作? 为每一个C结构体写一个对应的类? 那我的类怎么接收它的结构体呢?
谁给举个例子呀
多谢了, 在线等待..
问题点数:50、回复次数:10Top
1 楼steedhorse(晨星)回复于 2005-04-29 16:09:44 得分 40
哪有直接用Java接收结构体的。
通信协议必须明确规范每一个字段的类型、长度、字节顺序等信息,直接发结构体,那么除非两边都使用C语言编程,而且使用同样类型的CPU,使用同样的编译器编译,而且使用同样的编译选项。Top
2 楼xhjf777(古格国王)回复于 2005-04-29 16:18:06 得分 0
to steedhorse(晨星):
但是对方的c程序就是发送一个结构体数据过来,我现在的问题就是怎么接收它呢?
我把数据全部接收过来后,然后取前多少字节作为一个东西,再取从某个位置到某个位置的若干字节作为另外一个东西,但是不同的机器和操作系统上相同数据类型也未必占用相同的字节,我这样作也会存在问题吧?
我该怎么作呢?Top
3 楼HitXU(一天不学习,赶不上刘少奇)回复于 2005-04-29 16:25:54 得分 10
转贴::
近几天看到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方法发送,但字节顺序需要改为低在前。
这个问题稍后在讨论。
如有任何问题,请指正!
kingfish
2005.3.29
Top
4 楼HitXU(一天不学习,赶不上刘少奇)回复于 2005-04-29 16:26:19 得分 0
本部分提出另外一种做法, 供参考。
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
-----------------------------------------------------------------------------------------------------
如有任何问题,请指正!
kingfish
2005.3.30
Top
5 楼steedhorse(晨星)回复于 2005-04-29 16:32:16 得分 0
那你要明确两件事:
(1)对于多字节类型,比如int,它那边的CPU是高字节在前还是低字节在前,现在Intel X86系列的CPU用得多,一般是低字节在前。但如果他转换过了,那么可能就是高字节在前。
(2)他编译时是否按俺默认的结构体字对齐还是重新设过pack选项,如果是默认的,那么通常是按照4字节对齐,比如有个char[21]字段,后面跟一个int,那么取出21个字节的字符串之后,应该跳过3个字节取int。当然,如果它设置了pack(1),没有字节对齐,最好。Top
6 楼steedhorse(晨星)回复于 2005-04-29 16:34:20 得分 0
唉,真有些人不负责,编写网络通信程序,不管使用什么语言,都不能简单地假设通信对方也用C/C++,也用X86系列的CPU啊。Top
7 楼xhjf777(古格国王)回复于 2005-04-29 20:15:17 得分 0
to steedhorse(晨星),
是啊,所以我的疑问就是这样弄有太多的写死的情况,遇到某些机器和系统就得改程序,显然这样的程序是一个很失败的程序.
真的找不到一个好的解决方法了吗?Top
8 楼steedhorse(晨星)回复于 2005-04-29 20:24:08 得分 0
不过实际可能没那么糟糕,因为:
(1)实际中使用的可能还是Intel X86系列的CPU多一些,所以基本上可以按照低字节在前统一处理;
(2)如果原来程序的作者不太服责,那么说不定他根本没改过编译器的默认编译选项,就是采用默认的4字节对齐,也可以统一处理。
(3)也说不定你们的结构体里面没有需要填充的区域,比如没有char[M]后面接一个int字段的情况,而M不是4的整数倍,也没有连续奇数个short然后接着一个int的情况。
当然,还有一种可能,那就是原来程序的作者还是比较负责的,他已经采用编译选项取消了字对齐,而且采用字节顺序转换函数把所有的多字节字段都转换成了网络传输中通用的高字节在前的顺序,那样就更好了。Top
9 楼jack286(jack286)回复于 2005-07-18 21:33:19 得分 0
严重关注Top
10 楼jack286(jack286)回复于 2005-07-18 22:14:15 得分 0
大哥,你给的程序执行有错误啊Connection refused: connect
Top




