javatcpjerseyportlsof

Two processes listen on the same port (using Jersey), but not responding to same requests


I have two very simple apps listening on TCP HTTP 4466. Both use Jersey 2.X but one is a native-image and the other is a java UncompiledMain.java process (I'm trying to migrate to java native images instead of JIT compilation):

COMMAND   PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
1) java    71457 sarnobat   73u  IPv6 0x5e313f1de8147dd9      0t0  TCP *:4466 (LISTEN)
2) app     71552 sarnobat    5u  IPv6 0x5e313f1db096eb79      0t0  TCP localhost:4466 (LISTEN)

I'm using different runtime bindings for each (see details).

I know in more recent Linux kernel versions multiple listeners can bind to the same port but I don't know if that's related (besides, I'm using Mac OS X 10.15.7).

Can anyone suggest what I can do to understand why this is? Ultimately I wish to solve the problem so only one program handles all requests but I think I don't understand well enough some network basics.

Details

Sorry the code is messy - I was hoping to get it working before cleaning it up!

Server 1 (via JVM) - org.glassfish.jersey.jdkhttp.JdkHttpServerFactory

Responds to network requests (through an ssh tunnel).

JdkHttpServerFactory.createHttpServer(new URI("http://localhost:" + args[0] + "/"),
        new ResourceConfig(MyResource.class));
...
@javax.ws.rs.Path("")
public static class MyResource { // Must be public

    @GET
    @javax.ws.rs.Path("")
    @Produces("application/json")
    public Response list(@QueryParam("value") String iValue)
                throws JSONException, IOException {
        System.err.println("list()");
        System.out.println(iValue);

        return Response.ok().header("Access-Control-Allow-Origin", "*").type("application/json").build();
    }

Server 2 (native image) - org.glassfish.grizzly.http.server.HttpServer

Responds to local requests but not over network.

private static final URI BASE_URI = URI.create("http://localhost:4466/");
public static final String ROOT_PATH = "";
    
public static void main(String[] args) {
    try {
        System.out.println("\"Hello World\" Jersey Example App");

        final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, create(), true);
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                server.shutdownNow();
            }
        }));
        server.start();

...
public static ResourceConfig create() {
    final Resource.Builder resourceBuilder = Resource.builder(ROOT_PATH);

    resourceBuilder.addMethod("GET").handledBy(new Inflector<ContainerRequestContext, Response>() {

         @Override
         public Response apply(ContainerRequestContext data) {
             String iValue = data.getUriInfo().getQueryParameters().getFirst("value");
             System.err.println("list()");
             System.out.println(iValue);
             getMethodCalled = true;
             return Response.ok().header("Access-Control-Allow-Origin", "*").type("application/json").build();
          }
      });

Solution

  • While both servers bind to the same port, they bind to different IP addresses. The one binding to 127.0.0.1 gets all requests for 127.0.0.1, the one binding to 0.0.0.0 gets all IPv4 traffic (but no IPv6) except for 127.0.0.1 - since there is the other server with a more specific binding.