java - Java和C socket编程之间的结构数据通信

标签 java c sockets jakarta-ee

我有一个 Java 套接字 channel ,我正在发送对象数据并在 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 字节长。顺序:时间工作类型预算

在 Java 中,您已经创建了一个可变长度的缓冲区,其中包含可变长度的字符串,顺序为:jobtypebudgettime。从根本上说,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在他的评论中暗示,在通过位管道进行通信时,使用现有协议(protocol)通常会更好/更容易。这些协议(protocol)旨在解决许多可能变得相关的不同问题,即使是简单的 inter-process communications .

关于java - Java和C socket编程之间的结构数据通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27042319/

相关文章:

c - c中结构体中的数组

java - BufferedImage 始终从 ByteArrayInputStream 传入 null

python - 'socket.error : [Errno 9] Bad file descriptor' as I run my client

java - 避免使用Options进行空检查分支

java - 可调用任务未正确执行

java - 为什么将 ConcurrentNavigableMap 实现为跳跃列表?

c - 仅使用 1 个参数定义

java - 如何使用maven为Spring指定loadTimeWeaver

无法防止链表打印功能崩溃

c - 我应该使用什么 backlog 值?