我的任务是用C编写一个服务,该服务侦听一个命名或未命名的Windows OS管道(应该可以进行双向数据传输),并且将数据写入OS管道的"主机应用程序"应该是java程序.我不允许使用套接字(出于性能原因)或任何外部非默认库.

是否可以使用Java将数据写入命名/未命名的OS管道(如果可能的话,无需使用JNI将程序转换为C代码?)我一直在考虑运行一个CMD脚本,用java将其写入操作系统管道,但我很确定这会非常低效.我还研究了java Pipe类,但如果我理解正确的话,这只适用于JVM内部的线程间通信,而不是"真正的"OS管道.如何准确地将数据写入"真实"操作系统管道?性能对于这一点非常重要,因为我需要一个Java程序来与运行CUDA操作的C程序通信,所以我不能在发送/接收数据时浪费大量性能.

推荐答案

要求:

  • Java调用程序调用在其自己的进程中运行的C计算器程序
  • Java发送操作
  • C程序返回结果
  • 尽可能避免JNI/JNA

最简单的方法可能是从Java调用C程序并通过标准I/O进行通信.C程序可以通过循环中的stdin获得操作,进行计算,并通过stdout返回结果.

在Java中,实现这一点的核心机制是Process类.Oracle's documentation个州:

Process提供对ProcessBuilder启动的本机进程的控制.开始

为了避免死锁,我们交替地写一行要执行的操作,并读回一行结果.

使用stdinstdout的优点当然也是手动ad hocs可测试性,因为您可以在命令行上简单地调用C程序.顺便说一句,这种方法在Linux和macOS下也同样适用.

为了获得尽可能简单的测试用例,这里有一个C程序,它可以获得带有两个参数的加减运算符,计算结果并返回结果.当然,整个过程不包括CUDA和最小的错误处理,可能不满足详细的要求,但这可能是朝着正确方向的开始.

Java演示程序最终调用此C程序,并向C程序发送加减运算,并相应地输出返回的结果.然后,q命令终止C程序.

Java

package com.software7.test;

import java.io.*;

public class Caller {

    public static void main(String[] args) {
        Caller caller = new Caller();
        caller.runCCalculator();
    }

    private void runCCalculator() {
        try {
            String[] command = { "C:\\Users\\stephan\\source\\repos\\CCalculator\\x64\\Debug\\CCalculator.exe" };
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            Process process = processBuilder.start();

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));

            String[] ops = {"+ 1.1 2.2", "- 1024.123 512.123"};
            for (String op : ops) {
                bw.write(op);
                bw.write("\n");
                bw.flush();
                String result = br.readLine();
                if (result != null) {
                    System.out.println(op + " = " + result);
                }
            }
            bw.write("q\n");
            bw.flush();

            bw.close();
            br.close();
            System.out.println("Process exited with " + process.waitFor());
        } catch (IOException | InterruptedException exp) {
            exp.printStackTrace();
        }
    }

}

C

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static void error_exit(const char *msg);
static char readOp(const char *token);
static double readArg(const char *token);

int main(void) {
    char buf[128];
    char *ptr;

    while ((ptr = fgets(buf, sizeof(buf), stdin)) != NULL) {
        buf[strcspn(buf, "\n")] = 0;
        if (strcmp(ptr, "q") == 0) {
            break;
        }
        char *token = strtok(ptr, " ");
        char op = readOp(token);
        token = strtok(NULL, " ");
        double val1 = readArg(token);
        token = strtok(NULL, " ");
        double val2 = readArg(token);

        switch (op) {
            case '+':
                printf("%lf\n", val1 + val2);
                fflush(stdout);
                break;
            case '-':
                printf("%lf\n", val1 - val2);
                fflush(stdout);
                break;
            default:
                error_exit("unknown operator");
        }
    }
    return 0;
}

static char readOp(const char *token) {
    if (token != NULL) {
        return *token;
    } else {
        error_exit("no operator");
    }
}

static double readArg(const char *token) {
    double res;
    if (token != NULL) {
        char *end_ptr;
        res = strtod(token, &end_ptr);
        if (token == end_ptr || *end_ptr != '\0') {
            error_exit("invalid float operand");
        }
    } else {
        error_exit("invalid operand");
    }
    return res;
}

static void error_exit(const char *msg) {
    fprintf(stderr, "%s\n", msg);
    exit(1);
}

Result

+ 1.1 2.2 = 3.300000
- 1024.123 512.123 = 512.000000

Java相关问答推荐

Jooq外键关系

Java List with all combinations of 8 booleans

使用@MappdSuperClass扩展ParentClass&Won t继承ParentClass属性

使用Mockito进行的Junit测试失败

在Java 17中使用两个十进制数字分析时间时出错,但在Java 8中成功

如何在一行中使用Dijkstra中的Java Stream

为什么我的回收视图会显示重复的列表?

如何在不删除Java中已有内容的情况下覆盖文件内容?

如何获得凌空cookies ,并设置它在下一个请求- android

有没有办法在o(log(N))中以系统的方式将数组中的小块元素复制和移动到新增长的数组中的左侧?

如何在SWT菜单项文本中保留@字符

JavaFX,GridPane:在GridPane的列中生成元素将保持所有列的宽度

当使用不同的参数类型调用时,为什么围绕Objects.equals的类型安全包装不会失败?

在Java中比较同一多维数组的两个不同的字符串元素

在Spring Boot中使用咖啡因进行缓存-根据输出控制缓存

控制器建议异常处理

按长度排序字符串数组

ReturnedRect在升级后反转

将天数添加到ZonedDateTime不会更改时间

在JPanel上使用GridBagLayout并将JButton放在里面时出现问题