GRPC 客户端无法从 ubuntu 终端连接

问题描述 投票:0回答:1

我有简单的 grpc 客户端和服务器。

    public SensorRPCServer(ShareReadingsService service, int port) {
        this.service = service;
        this.port = port;
    }

    public void start() {
        try {
            server = ServerBuilder.forPort(port)
                    .addService(service)
                    .build()
                    .start();

            logger.info("Server started on " + port);

            //  Clean shutdown of server in case of JVM shutdown
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                logger.severe("Shutting down gRPC server since JVM is shutting down");
                SensorRPCServer.this.stop();
            }));
        } catch (IOException e) {
            logger.severe("GRPC server could not start up.");
        }
    }
    private static final Logger logger = Logger.getLogger(SensorRPCClient.class.getName());

    private final ManagedChannel channel;
    private final ShareReadingsGrpc.ShareReadingsBlockingStub blockingStub;

    public SensorRPCClient(String name, int port) {
        this.channel = ManagedChannelBuilder.forAddress(name, port).usePlaintext().build();
        blockingStub = ShareReadingsGrpc.newBlockingStub(channel);
    }

客户端和服务端在同一个项目中。意思是传感器是客户端(获取其他传感器数据)和服务器(向其他传感器提供读数)。

我从 ubuntu 终端构建并运行 java 项目,并传递 grpc 服务器运行的端口。

构建.gradle:

plugins {
    id 'java'
    id 'com.github.johnrengelman.shadow' version '8.1.1'  // Add this line
    id 'com.google.protobuf' version '0.9.4'
}

group = 'labos1.labosi'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.json:json:20240303'
    implementation 'com.opencsv:opencsv:5.9'

    implementation 'io.grpc:grpc-netty-shaded:1.68.0'
    implementation 'io.grpc:grpc-protobuf:1.68.0'
    implementation 'io.grpc:grpc-services:1.68.0'
    implementation 'io.grpc:grpc-stub:1.68.0'
    implementation 'javax.annotation:javax.annotation-api:1.3.2'

    testImplementation platform('org.junit:junit-bom:5.10.0')
    testImplementation 'org.junit.jupiter:junit-jupiter'
}

test {
    useJUnitPlatform()
}

shadowJar {
    manifest {
        attributes(
                'Main-Class': 'labos1.labosi.Main'  // Change this to your main class
        )
    }
}

sourceSets {
    main {
        java {
            srcDirs 'build/generated/source/proto/main/grpc'
            srcDirs 'build/generated/source/proto/main/java'
        }
    }
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.25.5"
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.68.0'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
        all().each {
            it.group = 'build'
        }
    }
}

我跑步

  1. ./gradlew 清理 Shadowjar
  2. java -jar build/libs/sensor-1.0-SNAPSHOT-all.jar 3000

如果我从 intelij 启动第二个实例,它会连接到 3000 上的 grpc 服务器并且工作正常。

但是如果我从终端启动第二个实例 java -jar build/libs/sensor-1.0-SNAPSHOT-all.jar 3001

当 grpc 客户端尝试连接到 3000 上的 grpc 服务器时,它失败了。

INFO: Neighbour found: {"port":3000,"latitude":45.77,"ip":"127.0.0.1","longitude":15.96}
Exception in thread "main" java.lang.IllegalArgumentException: Address types of NameResolver 'unix' for '127.0.0.1:3000' not supported by transport
public SensorRPCClient(String host, int port) {
 this.channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); <-- breaks here
 blockingStub = ShareReadingsGrpc.newBlockingStub(channel); 
 }
java ubuntu grpc
1个回答
0
投票

当 gRPC 无法正确解析提供的地址时,通常会发生 IllegalArgumentException 错误(“传输不支持 NameResolver 'unix' 的地址类型 'unix' for '127.0.0.1:3000'”),特别是在多实例设置中使用 localhost 和某些网络配置时。以下是解决此问题的一些解决方案:

  1. 验证IP地址格式 如果两个实例在不同的网络环境中运行,请尝试使用“localhost”或外部 IP 地址,而不是“127.0.0.1”。有时 127.0.0.1 在与多个实例的环回连接中表现不同。

按如下方式更新您的客户端实例化:

public SensorRPCClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress("localhost", port)
                                     .usePlaintext()
                                     .build();
blockingStub = ShareReadingsGrpc.newBlockingStub(channel);

} 2. 检查端口冲突和防火墙 确保每个实例确实绑定到单独的端口而不发生冲突。确认没有防火墙或网络安全设置阻止两个实例通过本地主机进行通信。

  1. 使用不同的 gRPC 通道 运行多个实例时,在创建新通道之前显式关闭任何现有通道可能会有所帮助。您可以向客户端和服务器添加关闭方法,以确保在启动新通道之前正确关闭通道:

客户端关闭示例

public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);

}

服务器关闭挂钩更新 确保服务器中的关闭挂钩设置正确,以避免端口绑定问题:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
logger.severe("Shutting down gRPC server since JVM is shutting down");
try {
    server.shutdown().awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

})); 4.检查Gradle构建配置 如果项目在 IntelliJ 中运行良好但在终端中失败,则可能是由于构建配置的差异造成的。通过刷新 Gradle 依赖项并确认 .proto 文件已正确生成,确保终端和 IDE 构建保持一致。

  1. 测试不同地址的绑定和连接 为了进一步诊断,您可以使用 ManagedChannelBuilder.forTarget("dns://127.0.0.1:3000").usePlaintext().build(); 测试客户端,其中 dns:// 可以提高地址解析的可靠性。

用于故障排除的示例代码调整 实施上述建议后,您的代码可能如下所示:

public SensorRPCClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress("localhost", port) // or use dns://
                                     .usePlaintext()
                                     .build();
blockingStub = ShareReadingsGrpc.newBlockingStub(channel);

}

完成这些调整后,尝试再次运行第二个实例,它应该可以解决 IllegalArgumentException 错误。

© www.soinside.com 2019 - 2024. All rights reserved.