[英]Strcture data communication between Java and C socket programming
我有一个Java套接字通道,正在发送对象数据并在C套接字中接收它。
Java代码::
//structure
class data
{
public String jobtype;
public String budget;
public String time ;
}
//creating a Socket Channel and sending data through it in java
Selector incomingMessageSelector = Selector.open();
SocketChannel sChannel = SocketChannel.open();
sChannel.configureBlocking(false);
sChannel.connect(new InetSocketAddress("localhost", 5000));
sChannel.register(incomingMessageSelector, SelectionKey.OP_CONNECT);
if(sChannel.finishConnect()==true)
{
sChannel.register(incomingMessageSelector, SelectionKey.OP_WRITE);
}
int len = 256;
ByteBuffer buf = ByteBuffer.allocate(len);
buf.putInt(len);
// Writing object of data in socket
buf.put(obj.jobtype.getBytes("US-ASCII"));
buf.put(obj.budget.getBytes("US-ASCII"));
buf.put(obj.time.getBytes("US-ASCII"));
buf.put((byte) 0);
buf.flip();
sChannel.write(buf);
C代码::
struct data
{
char time[50];
char jobtype[50];
char budget[50];
};
n = read(newsockfd, &size, sizeof(size));
struct data *result = malloc(size);
n = read(newsockfd, result, size);
printf("\njobtype :: %s\nbudget :: %s\ntime :: %s\n",result->jobtype,result->budget,result->time);
在Java中输入为:
jobtype = h1
budget = 20
time = 12
我在C中得到这些输出:
jobtype ::
budget ::
time :: h1
从Java发送到C的缓冲区在两种语言中都必须具有完全相同的定义(从字节角度考虑)。 在您的代码中并非如此。 您在Java中构造的缓冲区与在C中用于解释该缓冲区的struct
格式不同。 字符串的长度和字符串的顺序在发送者(Java)和接收者(C)之间都不匹配。 此外,已发送缓冲区的大小与基于已发送长度信息的预期缓冲区大小不匹配(即,您未发送正确长度的缓冲区)。
在C语言中,您定义了一个150字节长的结构,其中包含3个char
数组(字符串),每个50字节长。 随着一声令下: time
, jobtype
, budget
在Java中,您已经创建了一个可变长度的缓冲区,其可变长度的字符串的顺序为: jobtype
, budget
, time
。 从根本上讲,Java代码正在创建一个可变长度的缓冲区,其中C代码希望将其映射到固定长度的结构。
虽然这不是您想要的,但您的C程序正在获取您首先放置在缓冲区中的jobtype
字符串,并将其分配给time
。 当前是这样写的。
假设您保持C程序不变,那么创建和填充缓冲区的Java代码部分可能类似于:
public ByteBuffer createFixedLengthCString(String src, int len) {
//If the string is longer than len-1 it is truncated.
ByteBuffer cString = ByteBuffer.allocate(len);
if(src.length() > len - 1) {
//Using len-1 prevents the last 0 in the ByteBuffer from being
// overwritten. A final 0 is needed:C uses null (0) terminated strings.
cString.put(src.getBytes("US-ASCII"), 0, len-1);
} else {
//The string is not longer than the maximum length.
cString.put(src.getBytes("US-ASCII"));
}
//Already have null termination. Do not want to flip (would change length).
//Reset the position to 0.
cString.position(0);
return cString;
}
int maxBufLen = 256;
int payloadLen = 150
int cStringLen = 50;
ByteBuffer buf = ByteBuffer.allocate(maxBufLen);
//Tell C that the payload is 150 bytes long.
buf.putInt(payloadLen);
// Writing object data in the buffer
buf.put(createFixedLengthCString(obj.time, cStringLen));
buf.put(createFixedLengthCString(obj.jobtype, cStringLen));
buf.put(createFixedLengthCString(obj.budget, cStringLen));
//Use flip() here as it changes the length of bytes sent to the correct
// number (an int plus 150) and sets the position to 0, ready for reading.
buf.flip();
while(buf.hasRemaining()) {
//There is the possibility that a single call to write() will not
// write the entire buffer. Thus, loop until all data is written.
//There should be other conditions which cause us to break out of
// this loop (e.g. a maximum number of write attempts). Without such,
// if the channel is hung this is code will hang in this loop; effectively
// a blocking (for this code) write loop.
sChannel.write(buf);
}
该答案仅用于解决您在问题中发现的特定故障。 但是,所提供的代码实际上仅适用于在同一台机器上将有限的数据从一个进程传输到另一个进程的示例/测试。 即使这样,也应该有异常和错误处理,这里不包括。
正如EJP在其评论中所暗示的那样,在通过位管道进行通信时,使用已经存在的协议通常会更好/更容易。 这些协议旨在解决可能变得很重要的许多不同问题,即使在简单的进程间通信中也是如此 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.