Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UDP Dgram ERR_SOCKET_CANNOT_SEND #2484

Closed
Luuccc opened this issue Feb 24, 2020 · 4 comments
Closed

UDP Dgram ERR_SOCKET_CANNOT_SEND #2484

Luuccc opened this issue Feb 24, 2020 · 4 comments

Comments

@Luuccc
Copy link

Luuccc commented Feb 24, 2020

  • Node.js Version: v12.16.1
  • OS: Win 10
  • Scope (install, code, runtime, meta, other?): Runtime / Code
  • Module (and version) (if relevant): dgram

Hi, I've been trying to write a script that can send a message to a server (which I've hidden), which upon receiving, returns a response which I'm trying to listen for.
I seem to be having trouble with .bind(), but without it I'm listening to 0.0.0.0;, if you have any ideas, please let me know!
thanks

const dgram = require('dgram');
const buffer = require("buffer");
const server = dgram.createSocket('udp4');

var item = "Message";
var hostIP = "XX.XXX.XX.XXX";
var hostPort = 45239;

server.bind({
  address: hostIP,
  port: hostPort,
  exclusive: true
});

server.on("connect", function(){
    console.log("Connected");
});

server.on("message", function(message, info){
    console.log(info.address + ':' + info.port +' - ' + message);
});

server.on("listening", function(){
    var info = server.address();
    console.log("UDP Server listening to "  + info.address + ":" + info.port);
});

server.send(Buffer.from(item),hostPort,hostIP,function(error){
    if (error){
        client.close();
    }else{
        console.log("Data sent");
    }
});

And my error message being:

events.js:288
      throw er; // Unhandled 'error' event
      ^

Error [ERR_SOCKET_CANNOT_SEND]: Unable to send data
�[90m    at Socket.onListenError (dgram.js:525:22)�[39m
�[90m    at Object.onceWrapper (events.js:418:26)�[39m
�[90m    at Socket.emit (events.js:311:20)�[39m
�[90m    at dgram.js:341:14�[39m
�[90m    at processTicksAndRejections (internal/process/task_queues.js:85:21)�[39m
Emitted 'error' event on Socket instance at:
�[90m    at Socket.onListenError (dgram.js:525:8)�[39m
�[90m    at Object.onceWrapper (events.js:418:26)�[39m
    [... lines matching original stack trace ...]
�[90m    at processTicksAndRejections (internal/process/task_queues.js:85:21)�[39m {
  code: �[32m'ERR_SOCKET_CANNOT_SEND'�[39m
}
@bnoordhuis
Copy link
Member

You're trying to send data before the socket has been bound. Node tries to do that implicitly for you but the operation fails, presumably because either the address is already in use or because the bind address is wrong.

Either way, you should get a more legible error when you move the server.send(...) call inside your server.on("listening", ...) event listener. Right now, that ERR_SOCKET_CANNOT_SEND is masquerading the real error.

cc @cjihrig I see you added that in nodejs/node@5587ff1ccd9. It might be better to forward the original listen error?

@cjihrig
Copy link

cjihrig commented Feb 25, 2020

cc @cjihrig I see you added that in nodejs/node@5587ff1. It might be better to forward the original listen error?

That commit is over three years old, so I don't recall if I had any reason for implementing it that way, but it makes sense now to forward the original error.

@Luuccc
Copy link
Author

Luuccc commented Feb 25, 2020

You're trying to send data before the socket has been bound. Node tries to do that implicitly for you but the operation fails, presumably because either the address is already in use or because the bind address is wrong.

Either way, you should get a more legible error when you move the server.send(...) call inside your server.on("listening", ...) event listener. Right now, that ERR_SOCKET_CANNOT_SEND is masquerading the real error.

Thanks, I've tried nesting the event calls, and adding the connect event, which no-longer throws an error. When a successful connection occurs, the correct address is given, but it doesn't listen to the same ip/port.

As well as throwing an error on sending a message, which I couldn't find a reference to.

const dgram = require('dgram');
const buffer = require("buffer");
const server = dgram.createSocket('udp4');

var item = "Message";
var hostIP = "127.0.0.1";
var hostPort = 45239;

server.connect(hostPort,hostIP,function(){
    var info = server.address();
    console.log("Connected to " + info.address + ":" + info.port);
});

server.on("message", function(message, info){
    console.log(info.address + ':' + info.port +' - ' + message);
});

server.on("listening", function(){
    var info = server.address();
    console.log("Server listening to "  + info.address + ":" + info.port);
    server.send(Buffer.from(item),hostPort,hostIP,function(error){
        if (error){
            console.log(error);
            server.close();
        }else{
            console.log("Data sent");
        }
    });
});

Output

Server listening to 0.0.0.0:52870
Connected to 127.0.0.1:52870
Error: send EISCONN 127.0.0.1:45239
    at doSend (dgram.js:697:16)
    at defaultTriggerAsyncIdScope (internal/async_hooks.js:311:12)
    at afterDns (dgram.js:643:5)
    at processTicksAndRejections (internal/process/task_queues.js:85:21) {
  errno: 'EISCONN',
  code: 'EISCONN',
  syscall: 'send',
  address: '127.0.0.1',
  port: 45239
}

@Luuccc
Copy link
Author

Luuccc commented Feb 27, 2020

After trial and error, I ended up with this working script, sending a piece of data to a destination, and listening for its response. Where LOCAL_IP would normally be 192.168.X.Y , and HOST_IP being the destination IP.

var LOCAL_IP = "XXX.XXX.XX.XX"
var HOST_IP = "XX.XXX.XX.XXX";
var PORT = 45239;

var dgram = require("dgram");
var client = dgram.createSocket("udp4");

//Listen for repsonse locally
client.on("listening", function(){
    var adrInfo = client.address();
    console.log("Client listening on "  + adrInfo.address + ":" + adrInfo.port);
    var text = Buffer.from("Message");
    client.send(text,PORT,HOST_IP,function(error){
        if (error){
            console.log(error);
        }else{
            console.log("Sent " + text);
        }
    });
    client.on("message", function(message, remote){
        console.log("Recieved response as: " + message + " from " + remote.address + ":" + remote.port);
    });
});
//On error event display error
client.on('error',function(error){
    console.log('Error: ' + error);
    client.close();
});

//Binding to given location
client.bind(PORT, LOCAL_IP);
//Close socket after x ms
setTimeout(function(){client.close();},8000);

@Luuccc Luuccc closed this as completed Feb 27, 2020
cjihrig added a commit to cjihrig/node that referenced this issue Feb 28, 2020
When dgram socket implicit binding fails, an attempt is made to
clean up the send queue. This was originally implemented using
an 'error' handler that performed cleanup and then emitted a
fake error, which concealed the original error. This was done
to prevent cases where the same error was emitted twice. Now
that the errorMonitor event is available, use that to perform
the cleanup without impacting the actual error handling.

PR-URL: nodejs#31958
Refs: nodejs/help#2484
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
cjihrig added a commit to cjihrig/node that referenced this issue Feb 28, 2020
This error is no longer used within core. This commit removes it.

PR-URL: nodejs#31958
Refs: nodejs/help#2484
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@bnoordhuis @cjihrig @Luuccc and others