Socket Connection in NodeMCU Lua works as snippet, not from init.lua - sockets

I have the following code
conn = net.createConnection(net.TCP, 0)
conn:on("sent", function(sck,c)
print("Sent")
sck:close()
end)
conn:on("connection", function(sck,c)
print("Connected..")
sck:send("test")
end)
conn:connect(9090, "192.168.1.89")
print("Send data.")
This works fine when run as a snippet in ESPlorer, IE run live interpreter. I see the output "Connected.." and "Sent", and the message appears on the sever. When it is part of either the init.lua, or my mcu-temp.lua I don't even see the "Connected.." message.
The connection to WIFI is OK, and the board isn't reset between trying it "live" and from the file. I'm really stuck as to why it works OK one way and not the other.

The connection to WIFI is OK
I seriously doubt that. If you run from ESPlorer then yes, but not when you reboot the device.
Connecting to an AP takes a few seconds normally. You need to wait until it's connected until you can continue with the startup sequence. Remember: with NodeMCU most operations are asynchronous and event-driven, wifi.sta.connect() does NOT block.
Here's a startup sequence I borrowed, and adapted, from https://cknodemcu.wordpress.com/.
SSID = <tbd>
PASSWORD = <tbd>
function startup()
local conn = net.createConnection(net.TCP, 0)
conn:on("sent", function(sck, c)
print("Sent")
sck:close()
end)
conn:on("connection", function(sck, c)
print("Connected..")
sck:send("test")
end)
conn:connect(9090, "192.168.1.89")
print("Sent data.")
end
print("setting up WiFi")
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,PASSWORD)
wifi.sta.connect()
tmr.alarm(1, 1000, 1, function()
if wifi.sta.getip() == nil then
print("IP unavaiable, Waiting...")
else
tmr.stop(1)
print("Config done, IP is "..wifi.sta.getip())
print("You have 5 seconds to abort startup")
print("Waiting...")
tmr.alarm(0, 5000, 0, startup)
end
end)
Just two days ago I answered nearly the same question here on SO. See https://stackoverflow.com/a/37495955/131929 for an alternative solution.

Related

Unable to capture MQTT log callback

I am having trouble getting the on_log callback to trigger. I have used it on other programs w/o problems but this one is being difficult. I have included the relevant code snippets (I hope!). All other call backs are working fine. This program isn't threaded (except MQTT.start) so there aren't any other actions. Any suggestions where to look would be appreciated. fwiw, the problem I'm trying to track down is that MQTT stops responding after a few hours. The MQTT server is on a separate server, is used by numerous other processes and has no known issues.
# Set up MQTT - wait until we have an ipaddr so we know the network has been started
logger.debug("Waiting for ip address to be assigned")
while True:
ipaddr = get_local_IP()
if ipaddr is not None:
logger.info('IP address is {}'.format(ipaddr))
break
sleep(2.0)
logger.debug("Waiting for MQTT broker connection")
mqttc = mqtt.Client()
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe
while True:
try:
mqttc.connect("192.168.0.18", 1884, 30)
except IOError as e:
if e.errno != errno.ENETUNREACH:
raise
logger.warning('Network error - retrying')
sleep(15)
continue
logger.debug('Connect initiated without error')
break
mqttc.loop_start()
mqttc.on_log = on_log
while not MQ_link:
sleep(1)
def on_connect(mqttc, obj, flags, rc):
global MQ_link
logger.debug("Connected: rc = " + str(rc))
if rc == 0:
MQ_link = True
def on_log(mqttc, obj, level, string):
verb = string.split('(').strip()
if verb[0] not in ['Sending PINGREQ', 'Received PINGRESP']:
logger.debug('LOG: ' + string)

Async sockets in D

Okay this is my first question here on Stack Overflow, so bare over with it if I'm not asking properly.
Basically I'm trying to code some asynchronous sockets using std.socket, but I'm not sure if I've understood the concept correct. I've only ever worked with asynchronous sockets in C# and in D it seem to be on a much lower level. I've researched a lot and looked up a lot of code, documentation etc. both for D and C/C++ to get an understanding, however I'm not sure if I understand the concept correctly and if any of you have some examples. I tried looking at splat, but it's very outdated and vibe seems to be too complex just for a simple asynchronous socket wrapper.
If I understood correctly there is no poll() function in std.socket so you'd have to use SocketSet with a single socket on select() to poll the status of the socket right?
So basically how I'd go about handling the sockets is polling to get the read status of the socket and if it has a success (value > 0) then I can call receive() which will return 0 for disconnection else the received value, but I'd have to keep doing this until the expected bytes are received.
Of course the socket is set to nonblocked!
Is that correct?
Here is the code I've made up so far.
void HANDLE_READ()
{
while (true)
{
synchronized
{
auto events = cast(AsyncObject[int])ASYNC_EVENTS_READ;
foreach (asyncObject; events)
{
int poll = pollRecv(asyncObject.socket.m_socket);
switch (poll)
{
case 0:
{
throw new SocketException("The socket had a time out!");
continue;
}
default:
{
if (poll <= -1)
{
throw new SocketException("The socket was interrupted!");
continue;
}
int recvGetSize = (asyncObject.socket.m_readBuffer.length - asyncObject.socket.readSize);
ubyte[] recvBuffer = new ubyte[recvGetSize];
int recv = asyncObject.socket.m_socket.receive(recvBuffer);
if (recv == 0)
{
removeAsyncObject(asyncObject.event_id, true);
asyncObject.socket.disconnect();
continue;
}
asyncObject.socket.m_readBuffer ~= recvBuffer;
asyncObject.socket.readSize += recv;
if (asyncObject.socket.readSize == asyncObject.socket.expectedReadSize)
{
removeAsyncObject(asyncObject.event_id, true);
asyncObject.event(asyncObject.socket);
}
break;
}
}
}
}
}
}
So basically how I'd go about handling the sockets is polling to get the read status of the socket
Not quite right. Usually, the idea is to build an event loop around select, so that your application is idle as long as there are no network or timer events that need to be handled. With polling, you'd have to check for new events continuously or on a timer, which leads to wasted CPU cycles, and events getting handled a bit later than they occur.
In the event loop, you populate the SocketSets with sockets whose events you are interested in. If you want to be notified of new received data on a socket, it goes to the "readable" set. If you have data to send, the socket should be in the "writable" set. And all sockets should be on the "error" set.
select will then block (sleep) until an event comes in, and fill the SocketSets with the sockets which have actionable events. Your application can then respond to them appropriately: receive data for readable sockets, send queued data for writable sockets, and perform cleanup for errored sockets.
Here's my D implementation of non-fiber event-based networking: ae.net.asockets.

How to check a socket is closed or not in luasocket library?

I am writing a server using Lua programming language, and the network layer is based on LuaSocket.
And I cannot find any method to detect a socket is closed or not in its reference manual except by just try to read data from it(it will return nil and string 'close' when calling that).
My code looks like this:
local socket = require 'socket'
local server = socket.tcp()
local port = 9527
server:bind('*', port)
local status, errorMessage = server:listen()
if status == 1 then
printf('Server is launched successfully on port %u', port)
else
printf('Server listen failed, error message is %s', errorMessage)
return
end
local sockets = {server}
while true do
local results = socket.select(sockets)
for _, sock in ipairs(results) do
if sock == server then
local s = server:accept()
callback('Connected', s)
table.insert(sockets, s)
printf('%s connected', s:getsockname())
else
-- trying to detect socket is closed
if sock:isClosed() then
callback('Disconnected', sock)
for i, s in ipairs(sockets) do
if s == sock then
table.remove(sockets, i)
break
end
end
printf('%s disconnected', sock:getsockname())
else
callback('ReadyRead', sock)
end
end
end
end
except by just try to read data from it (it will return nil and string 'close' when calling that).
I'm not aware of any other method. Why doesn't checking the result from reading a socket work for you?
You need to use settimeout to make the call non-blocking and check the error returned for closed (not close). You can read one byte and store it or you can try reading zero bytes.

Getting value from Go channel

I have a go-routine which is listening for TCP connections and send these on a channel back to the main loop. The reason I'm doing this in a go-routine is to make this listening non-blocking and be able to handle active connections simultaneously.
I have implemented this with a select statement with an empty default case like this:
go pollTcpConnections(listener, rawConnections)
for {
// Check for new connections (non-blocking)
select {
case tcpConn := <-rawConnections:
currentCon := NewClientConnection()
pendingConnections.PushBack(currentCon)
fmt.Println(currentCon)
go currentCon.Routine(tcpConn)
default:
}
// ... handle active connections
}
Here is my pollTcpConnections routine:
func pollTcpConnections(listener net.Listener, rawConnections chan net.Conn) {
for {
conn, err := listener.Accept() // this blocks, afaik
if(err != nil) {
checkError(err)
}
fmt.Println("New connection")
rawConnections<-conn
}
}
The problem is that I never recieve these connections. If I do it in a blocking way, like this:
for {
tcpConn := <-rawConnections
// ...
}
I recieve the connections, but it blocks... I have tried buffering the channel as well, but the same thing happens. What am I missing here?
it's a little hard to tell why you're not seeing any connections based on the existing code. One problem with your sample is that you have an empty default case in a select statement, and then we can't see what else is happening in this for loop. The way you've written it, that loop might never yield to the scheduler. You're basically saying "get a thing from the channel. don't have one? ok, start over. get a thing from the channel!", but you never actually wait. When you do some action that blocks your goroutine, that goroutine yields to the scheduler. So when you do a channel read in the normal fashion, if there's no value to be read, that goroutine is blocked reading. Since it's blocked, it also yields to the scheduler to allow other goroutines to continue executing on the underlying thread. I'm fairly certain this is why your select with an empty default is breaking; you're causing that goroutine to loop infinitely on the for loop without ever yielding to the scheduler.
It's not clear what the role of pendingConnections is, or whether it's needed at all.
The other thing that's impossible to tell from the behavior is what your checkError function does. It doesn't, for example, continue to the top of the for loop, or bail.
Anyway, it looks like this is more complicated than it needs to be. Just have a function that takes the new connection as it's one parameter, and then launch that in a new goroutine when it connects. I always write it like this:
func handleConnection(c net.Conn) {
// do something with your connection here.
}
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
// do something with your error. You probably want to break or return here.
break
}
// handle each connection in a new goroutine
go handleConnection(conn)
}
this is more or less exactly what they do in the documentation.

Send commands over socket, but wait every time for response (Node.js)

I need to send several commands over telnet to a server. If I try to send them without a time delay between every command, the server freaks out:
var net = require('net');
var conn = net.createConnection(8888, 'localhost');
conn.on('connect', function() {
conn.write(command_1);
conn.write(command_2);
conn.write(command_3);
//...
conn.write(command_n);
})
I guess the server needs some time to respond to command n before I send it command n+1. One way is to write something to the log and fake a "wait":
var net = require('net');
var conn = net.createConnection(8888, 'localhost');
conn.on('connect', function() {
console.log('connected to server');
console.log('I'm about to send command #1');
conn.write(command_1);
console.log('I'm about to send command #2');
conn.write(command_2);
console.log('I'm about to send command #3');
conn.write(command_3);
//...
console.log('I'm about to send command #n');
conn.write(command_n);
})
It might also be the fact that conn.write() is asynchronous, and putting one command after another doesn't guranty the correct order??
Anyway, what is the correct pattern to assure correct order and enough time between two consecutive commands, for the server to respond?
First things first: if this is truly a telnet server, then you should do something with the telnet handshaking (where terminal options are negotiated between the peers, this is the binary data you can see when opening the socket).
If you don't want to get into that (it will depend on your needs), you can ignore the negotiation and go straight to business, but you will have to read this data and ignore it yourself.
Now, in your code, you're sending the data as soon as the server accepts the connection. This may be the cause of your troubles. You're not supposed to "wait" for the response, the response will get to you asynchronously thanks to nodejs :) So you just need to send the commands as soon as you get the "right" response from the server (this is actually useful, because you can see if there were any errors, etc).
I've tried this code (based on yours) against a device I've got at hand that has a telnet server. It will do a login and then a logout. See how the events are dispatched according to the sever's response:
var net = require('net');
var conn = net.createConnection(23, '1.1.1.1');
var commands = [ "logout\n" ];
var i = 0;
conn.setEncoding('ascii');
conn.on('connect', function() {
conn.on('login', function () {
conn.write('myUsername\n');
});
conn.on('password', function () {
conn.write('myPassword\n');
});
conn.on('prompt', function () {
conn.write(commands[i]);
i++;
});
conn.on('data', function(data) {
console.log("got: " + data + "\n");
if (data.indexOf("login") != -1) {
conn.emit('login');
}
if (data.indexOf("password") != -1) {
conn.emit('password');
}
if (data.indexOf(">#") != -1) {
conn.emit('prompt');
}
});
});
See how the commands are in an array, where you can iteratively send them (the prompt event will trigger the next command). So the right response from the server is the next prompt. When the server sends (in this case) the string ># another command is sent.
Hope it helps :)
The order of writes is guaranteed. However:
You must subscribe to data event. conn.on('data', function(data)
{}) will do.
You must check return values of writes - if a write
fails, you must wait for 'drain' event. So you should check if any
write really fails and if it does then fix the problem. If it
doesn't - then you can leave current dirty solution as is.
You
must check if your server supports request piplining (sending
multiple requests without waiting for responses). If it doesn't -
you must not send next request before receiving a data event after
the previous one.
You must ensure that the commands you send are real telnet commands - telnet expects a \0 byte after \r\n (see the RFC), so certain servers may freak if \0 is not present.
So:
var net = require('net');
var conn = net.createConnection(8888, 'localhost');
conn.on('connect', function() {
console.log(conn.write(command_1) &&
conn.write(command_2) &&
conn.write(command_3) &&
//...
conn.write(command_n))
})
conn.on('data', function () {})
If it writes false - then you must wait for 'drain'. If it writes true - you must implement waiting. I discourage the event-based solution and suggest to look at using async or Step NPM modules instead.