asyncio socket for 127.0.0.1 vs 127.0.0.3 - network-programming

Not able to figure out what is wrong when I give address as 127.0.0.3(TimeoutError), whereas the following code works fine when the addr is 127.0.0.1(ConnectionRefusedError). Note that in both the cases, the server is not up.
Can anyone elaborate why different errors are being shown up here, and ConnectionResfusedError is quick, whereas the TimeoutError takes time.
import asyncio
async def handle_connection(addr, port, message):
reader, writer = await asyncio.open_connection(addr, port)
print(f'Send: {message!r}')
writer.write(message.encode())
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
print('Close the connection')
writer.close()
if __name__ == "__main__":
addr = '127.0.0.3'
port = 8888
try:
asyncio.run(handle_connection(addr, port, 'request'))
except Exception as err:
print(f'Error: {err}'

Related

UMQTT.simple function to check client.ping() call back

I am trying to get my head around UMQTT.simple. I am looking to handle instances in which my server might disconnect for a reboot. I want to check whether the client is connected, and if not, wait some period and try to reconnect.The guidance seems to be to use client.ping() for this (How to check Micropython umqtt client is connected?).
For the MQTT.paho client I see there is a way to access ping responses in the logs function (see here: http://www.steves-internet-guide.com/mqtt-keep-alive-by-example/). For UMQTT the docs indicate that ping response is handled automatically by wait_msg(): Ping server (response is automatically handled by wait_msg() (https://mpython.readthedocs.io/en/master/library/mPython/umqtt.simple.html). There does not appear to be any analogous logs function mentioned in the UMQTT.simple docs.
This is confounding for a couple of reasons:
If i use client.wait_msg() how do I call client.ping()? client.wait_msg() is a blocking function, so I can't make the ping. The system just disconnects when the keepalive time is reached.
If I call client.check_msg(), and client.ping() intermittently, I can't access the callback. My callback function doesn't have parameters to access pingresponse (params are f(topic, msg) in the docs).
The way I am solving this for now is to set a bunch of try-except calls on my client.connect and then connect-subscribe functions, but its quite verbose. Is this the way to handle or can i take advantage of the pingresponse in UMQTT.simple?
Below is a sample of the code i am running:
#Set broker variables and login credentials
#Connect to the network
#write the subscribe call back
def sub_cb(topic, msg):
print((topic, msg))
#write a function that handles connecting and subscribing
def connect_and_subscribe():
global CLIENT_NAME, BROKER_IP, USER, PASSWORD, TOPIC
client = MQTTClient(client_id=CLIENT_NAME,
server=BROKER_IP,
user=USER,
password=PASSWORD,
keepalive=60)
client.set_callback(sub_cb)
client.connect()
client.subscribe(TOPIC)
print('Connected to MQTT broker at: %s, subscribed to %s topic' % (BROKER_IP, TOPIC))
return(client) #return the client so that i can do stuff with it
client = connect_and_subscribe()
#Check messages
now = time.time()
while True:
try:
client.check_msg()
except OSError as message_error: #except if disconnected and check_msg() fails
if message_error == -1:
time.sleep(30) #wait for reboot
try:
client = connect_and_subscribe() #Try connect again to the server
except OSError as connect_error: #If the server is still down
time.sleep(30) #wait and try again
try:
client = connect_and_subscribe()
except:
quit() #Quite so that i don't get stuck in a loop
time.sleep(0.1)
if time.time() - now > 80: #ping to keepalive (60 * 1.5)
client.ping()
now = time.time() #reset the timer

How to connect to KaaIOT MQTT broker

I want to connect my KaaIOT cloud and subscribe a topic to show result from terminal. I do not know where to get the topic name to subscribe with. I had read the KaaIOT documentation but still cannot have a clear idea on it. Could someone help me with a sample code for me to reference?
KaaIOT Information
appVersion.name: c184ijqrqa51q5haskp0-v1
appVersion.registeredDate: 2021-03-16T05:59:54.185Z
createdDate: 2021-03-16T05:59:54.186Z
endpointId: fc2c5833-77c5-445a-89a0-9b0e7498c048
model: Raspberry Pi (192.168.0.171)
metadataUpdatedDate: 2021-03-17T09:13:01.809Z
Sample Code
import itertools
import json
import queue
import random
import string
import sys
import time
import paho.mqtt.client as mqtt
KPC_HOST = "mqtt.cloud.kaaiot.com" # Kaa Cloud plain MQTT host
KPC_PORT = 1883 # Kaa Cloud plain MQTT port
APPLICATION_VERSION = "" # Paste your application version
ENDPOINT_TOKEN = "" # Paste your endpoint token
class MetadataClient:
def __init__(self, client):
self.client = client
self.metadata_by_request_id = {}
self.global_request_id = itertools.count()
get_metadata_subscribe_topic = f'kp1/{APPLICATION_VERSION}/epmx/{ENDPOINT_TOKEN}/get/#'
self.client.message_callback_add(get_metadata_subscribe_topic, self.handle_metadata)
def handle_metadata(self, client, userdata, message):
request_id = int(message.topic.split('/')[-2])
if message.topic.split('/')[-1] == 'status' and request_id in self.metadata_by_request_id:
print(f'<--- Received metadata response on topic {message.topic}')
metadata_queue = self.metadata_by_request_id[request_id]
metadata_queue.put_nowait(message.payload)
else:
print(f'<--- Received bad metadata response on topic {message.topic}:\n{str(message.payload.decode("utf-8"))}')
def get_metadata(self):
request_id = next(self.global_request_id)
get_metadata_publish_topic = f'kp1/{APPLICATION_VERSION}/epmx/{ENDPOINT_TOKEN}/get/{request_id}'
metadata_queue = queue.Queue()
self.metadata_by_request_id[request_id] = metadata_queue
print(f'---> Requesting metadata by topic {get_metadata_publish_topic}')
self.client.publish(topic=get_metadata_publish_topic, payload=json.dumps({}))
try:
metadata = metadata_queue.get(True, 5)
del self.metadata_by_request_id[request_id]
return str(metadata.decode("utf-8"))
except queue.Empty:
print('Timed out waiting for metadata response from server')
sys.exit()
def patch_metadata_unconfirmed(self, metadata):
partial_metadata_udpate_publish_topic = f'kp1/{APPLICATION_VERSION}/epmx/{ENDPOINT_TOKEN}/update/keys'
print(f'---> Reporting metadata on topic {partial_metadata_udpate_publish_topic}\nwith payload {metadata}')
self.client.publish(topic=partial_metadata_udpate_publish_topic, payload=metadata)
def main():
# Initiate server connection
print(f'Connecting to Kaa server at {KPC_HOST}:{KPC_PORT} using application version {APPLICATION_VERSION} and endpoint token {ENDPOINT_TOKEN}')
client_id = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
client = mqtt.Client(client_id=client_id)
client.connect(KPC_HOST, KPC_PORT, 60)
client.loop_start()
metadata_client = MetadataClient(client)
# Fetch current endpoint metadata attributes
retrieved_metadata = metadata_client.get_metadata()
print(f'Retrieved metadata from server: {retrieved_metadata}')
# Do a partial endpoint metadata update
metadata_to_report = json.dumps({"model": "BFG 9000", "mac": "00-14-22-01-23-45"})
metadata_client.patch_metadata_unconfirmed(metadata_to_report)
time.sleep(5)
client.disconnect()
if __name__ == '__main__':
main()
I have established a communication with EMQX broker by using MQTT protocol. But I don't know about KaaIoT much but this might help you. As I went through your code, I didn't see the part where you have subscribed to the topic(correct me if I am wrong). You can refer this. I have implemented the sub pub model and below is the subscriber code which runs fine for EMQX broker. You can try it for KaaIoT.
import paho.mqtt.client as mqtt
import time
import logging
def on_connect(client, userdata, flags, rc):
logging.info("Connected flags"+str(flags)+"result code " + str(rc)+ "client1_id")
client.connected_flag=True
def on_message(client, userdata, message):
print("Received message: " ,str(message.payload.decode("utf-8")))
def on_disconnect(client, userdata, rc):
if rc != 0:
print("Unexpected MQTT disconnection. Will auto-reconnect")
client = mqtt.Client('''Your client id string''')
client.connect("mqtt.cloud.kaaiot.com", 1883, 60)
client.subscribe('''Your topic name (mentioned where data is published)''',qos=1)
client.on_connect = on_connect
client.on_message=on_message
client.on_disconnect = on_disconnect
client.loop_forever()

ESP8266, NodeMCU, soft AP - UDP server-like soft AP, independent access point

I am using NodeMCU (with ESP8266-E) with an upgraded firmware. All basic commands work perfectly but there is one problem.
I wanted to create an independent access point, which could have a behaviour like a UDP server. That means without direct connection to any other access points. A simple UDP server like soft AP.
I followed these steps:
I have uploaded a new firmware to NodeMCU.
I have downloaded ESPlorer for better work with NodeMCU.
I have uploaded the source code below.
I have connected to the NodeMCU access point on my desktop.
I have sent some strings to the NodeMCU using a Java UDP client program.
I have looked at the messages on ESPlorer.
NodeMCU has not received any such strings.
--
print("ESP8266 Server")
wifi.setmode(wifi.STATIONAP);
wifi.ap.config({ssid="test",pwd="12345678"});
print("Server IP Address:",wifi.ap.getip())
-- 30s timeout for an inactive client
srv = net.createServer(net.UDP, 30)
-- server listens on 5000, if data received, print data to console
srv:listen(5000, function(sk)
sk:on("receive", function(sck, data)
print("received: " .. data)
end)
sk:on("connection", function(s)
print("connection established")
end)
end)
When I tried to send a message using a Java application, there was no change in ESPlorer. Not even when I tried to send a message using the Hercules program (great program for TCP, UDP communication).
I guess that maybe it will be the wrong IP address. I am using the IP address of the AP and not the IP address of the station.
In other words I am using this address: wifi.ap.getip() and not this address wifi.sta.getip() for connections to the UDP server. But sta.getip() returns a nil object. Really I don't know.
I will be glad for any advice.
Thank you very much.
Ok, let's restart this since you updated the question. I should have switched on my brain before I gave you the first hints, sorry about this.
UDP is connectionless and, therefore, there's of course no s:on("connection"). As a consequence you can't register your callbacks on a socket but on the server itself. It is in the documentation but it's easy to miss.
This should get you going:
wifi.setmode(wifi.STATIONAP)
wifi.ap.config({ ssid = "test", pwd = "12345678" })
print("Server IP Address:", wifi.ap.getip())
srv = net.createServer(net.UDP)
srv:listen(5000)
srv:on("receive", function(s, data)
print("received: " .. data)
s:send("echo: " .. data)
end)
I ran this against a firmware from the dev branch and tested from the command line like so
$ echo "foo" | nc -w1 -u 192.168.4.1 5000
echo: foo
ESPlorer then also correctly printed "received: foo".
This line is invalid Lua code. connected is in the wrong place here. you can't just put a single word after a function call.
print(wifi.ap.getip()) connected
I guess you intended to do something like
print(wifi.ap.getip() .. " connected")
Although I think you should add som error handling here in case wifi.ap.getip() does not return an IP.
Here you do not finish the function definition. Neither did you complete the srv:on call
srv:on("receive", function(srv, pl)
print("Strings received")
srv:listen(port)
I assume you just did not copy/paste the complete code.

How to check whether IMAP-IDLE works?

I noticed that my IMAP server seems to support IDLE but notifications arrive late. So I was asking myself: How can I check whether IDLE works (or is it my mail client)?
Inspired by http://pymotw.com/2/imaplib/, you can use following Python scripts to check if and how fast push notification via IDLE work:
imaplib_connect.py
import imaplib
import ConfigParser
import os
def open_connection(verbose=False):
# Read the config file
config = ConfigParser.ConfigParser()
config.read([os.path.abspath('settings.ini')])
# Connect to the server
hostname = config.get('server', 'hostname')
if verbose: print 'Connecting to', hostname
connection = imaplib.IMAP4_SSL(hostname)
# Login to our account
username = config.get('account', 'username')
password = config.get('account', 'password')
if verbose: print 'Logging in as', username
connection.login(username, password)
return connection
if __name__ == '__main__':
c = open_connection(verbose=True)
try:
print c
finally:
c.logout()
print "logged out"
imaplib_idlewait.py
import imaplib
import pprint
import imaplib_connect
imaplib.Debug = 4
c = imaplib_connect.open_connection()
try:
c.select('INBOX', readonly=True)
c.send("%s IDLE\r\n"%(c._new_tag()))
print ">>> waiting for new mail..."
while True:
line = c.readline().strip();
if line.startswith('* BYE ') or (len(line) == 0):
print ">>> leaving..."
break
if line.endswith('EXISTS'):
print ">>> NEW MAIL ARRIVED!"
finally:
try:
print ">>> closing..."
c.close()
except:
pass
c.logout()
settings.ini
[server]
hostname: yourserver.com
[account]
username: yourmail#yourserver.com
password: yoursecretpassword
After creating those files, just call
python imaplib_idlewait.py
Please note, that this scripts does not close gracefully if you press CTRL+C (readline() is blocking and is not terminated by close()), however, for testing it should be good enough.
Also note, that most mail server terminate the connection after 30 minutes. After that you have to re-open the connection, e.g. like demonstrated here: http://blog.mister-muffin.de/2013/06/05/reliable-imap-synchronization-with-idle-support

How to telnet an address?

I'm trying to understand the socket class and i'm using the following example to implement a server sample
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on IP [" ..ip.. "] and port [" .. port .. "]")
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
while true do
-- wait for a connection from any client
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then
client:send(line .. "\n")
end
-- done with client, close the object
client:close()
end
But now the question is, how can I telnet for example the address localhost:8080 via lua?
EDIT:
I forgot to tell something, I donĀ“t even can telnet on cmd. When I type the command:
telnet ip port
it always says "connection lost" after I send a message. What am I doing wrong?
First, follow the instructions from here to enable telnet in Windows 7:
Go to Control Panel
Find Turn Windows features on or off under Programs (depending on layout)
Find Telnet client and enable it.
Once you've done that, it should work as expected.
Done!
local socket = require("socket")
local server = socket.connect(ip, port)
local ok, err = server:send("RETURN\n")
if (err ~= nil) then
print (err)
else
while true do
s, status, partial = server:receive(1024)
print(s or partial)
if (status == "closed") then
break
end
end
end
server:close()

Resources