2

My use case (webservice):

Multiple clients => Webserver => Message to C program through UNIX domain socket.

I've been using Apache + PHP for the webserver layer, but I'm currently in the process of replacing it with Node.js.

The webservice gets up to 100 requests/sec, so it's a very real scenario that the C program will be busy when a new request comes in. PHP handles this just fine, but Node.js often fails with the error:

{
  "code": "EAGAIN",
  "errno": "EAGAIN",
  "syscall": "connect",
  "address": "/tmp/service.sock"
}

I'm assuming this is because PHP performs some kind of message queue/retry that will ensure all messages are sent to the C program (which Node.js does not).

Is there a simple way to do the same in Node.js or will have I have to implement a custom message queue?

C socket creation:

int listenSocket, newSocket;
struct sockaddr_un localAddress, remoteAddress;

// Create socket
if ((listenSocket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1){
  printf("Error opening listener socket");
  exit(1);
}

// Configure socket
localAddress.sun_family = AF_UNIX; // Set UNIX domain socket type
strcpy(localAddress.sun_path, "/tmp/service.sock");
unlink(localAddress.sun_path); // Remove any previous instances of the socket

// Open listener socket
int len = strlen(localAddress.sun_path) + sizeof(localAddress.sun_family);
if (bind(listenSocket, (struct sockaddr *)&localAddress, len) == -1){
  printf("Error binding socket at %s", localAddress.sun_path);
  exit(1);
}
chmod(localAddress.sun_path, 0777);

// Listen for new connections on the listener socket
if (listen(listenSocket, 5) == -1){
  printf("Error listening on listener socket");
  exit(1);
}

// Handle new connections
while(!shutdown){
  printf("Waiting for a connection...\n");

  // Accept new connection
  int sizeofRemoteAddress = sizeof(remoteAddress);
  if ((newSocket = accept(listenSocket, (struct sockaddr *)&remoteAddress, &sizeofRemoteAddress)) == -1){
    printf("Error accepting new connection: %s\n", strerror(errno));
    continue;
  }

  // Read and handle data from client...
}

Connecting to the socket in PHP:

$socket = @socket_create(AF_UNIX, SOCK_STREAM, 0);
if (!$socket) return false;

$connected = @socket_connect($socket, "/tmp/service.sock");
if (!$connected) return false;

// Send message to server and read response...

Connecting to the socket in Node.js:

new Promise(function(resolve, reject){
  var socket = Net.connect("/tmp/service.sock");

  socket.on("error", function(err){
    reject(err);
  });

  socket.on("connect", function(){
    socket.write(message);
  });

  socket.on("data", function(data){
    socket.end();
    resolve(data.toString("UTF-8"));
  });
});

1 Answer 1

1

EAGAIN is an expected condition when the system call was interrupted. You should simply repeat the same call while you get the EAGAIN error code. In typical C programs you'll see tons of while (returnCode == -1 && errno == EAGAIN) style of loops. If you expect many interrupts, you could first disable interrupts (not sure how this is done in node.js) do your system call, then enable interrupts again. Not sure if this answer is any good for a node.js application but I thought I mention it anyway.

Sign up to request clarification or add additional context in comments.

1 Comment

I'll interpret your answer as "No, implement a message queue". Your explanation makes pretty good sense because I was seeing some heavy CPU load from the ksoftirqd processes (interrupt handlers) and I found some code similar to your example in the PHP source. I did end up making the message queue in the meantime - a solution that probably yields better performance and is "nicer" than a while (EAGAIN) loop

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.