0

Hello i am working on a raspberry PI which is supposed to send continuously data from sensors connected to this PI so here is my script :

import logging
import asyncio
from grovepi import*

import time
import json

from aiocoap import *

logging.basicConfig(level=logging.INFO)

def createMsg( file,value ) :
    f= open(file + "Config.json")
    data = json.load(f)
    f.close()
    data["timestamp"] = str(round(time.time(), 3))
    data["value"] = value
    return json.dumps( data )

async def main():

    #analog
    soundSensorPort=0
    lightSensorPort=1

    #digital
    motionSensorPort=2
    tempSensorPort=2
    ultrasonicSensorPort=5
    pinMode(tempSensorPort, "INPUT")

    while True:
        context = await Context.create_client_context()

        await asyncio.sleep(2)
        [ tempSensorValue, humiditySensorValue ]  = dht(tempSensorPort, 0)
        tempMsg = createMsg( "temperatureSensor", tempSensorValue)
        humidityMsg = createMsg( "humiditySensor", humiditySensorValue)

        payloadTemp = tempMsg.encode('utf-8')
        payloadHumidity = humidityMsg.encode('utf-8')
        requestTemp = Message(code=PUT, payload=payloadTemp)
        requestHumidity = Message(code=PUT, payload=payloadHumidity)

        requestTemp.opt.uri_host = '129.6.60.38'
        requestHumidity.opt.uri_host = '129.6.60.38'

        requestTemp.opt.uri_path = ("other", "sensors","temperature")
        requestHumidity.opt.uri_path = ("other", "sensors","humidity")

        responseTemp = await context.request(requestTemp).response
        responseHumidity = await context.request(requestHumidity).response

        print('Result: %s\n%r'%(responseTemp.code, responseTemp.payload))
        print('Result: %s\n%r'%(responseHumidity.code, responseHumidity.payload))

if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

but after maybe 20/25 mins of running i have this error :

File "clientPUT.py", line 84, in <module>
  File "/usr/lib/python3.5/asyncio/base_events.py", line 466, in run_until_complete
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
  File "clientPUT.py", line 63, in main
  File "clientPUT.py", line 27, in createMsg
OSError: [Errno 24] Too many open files: 'temperatureSensorConfig.json'

This is really weird because i close the file just after reading it and loading it in 'f' so if someone have ay ideas it would be very helpful

EDIT 0 : run sudo ls -l /proc/4223/fd returns :

total 0
lrwx------ 1 root root 64 Jun 20 15:38 0 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 20 15:38 1 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 20 15:39 10 -> socket:[155862]
lrwx------ 1 root root 64 Jun 20 15:39 11 -> socket:[155876]
lrwx------ 1 root root 64 Jun 20 15:39 12 -> socket:[155877]
lrwx------ 1 root root 64 Jun 20 15:39 13 -> socket:[155878]
lrwx------ 1 root root 64 Jun 20 15:39 14 -> socket:[155879]
lrwx------ 1 root root 64 Jun 20 15:39 15 -> socket:[155880]
lrwx------ 1 root root 64 Jun 20 15:39 16 -> socket:[155882]
lrwx------ 1 root root 64 Jun 20 15:39 17 -> socket:[154981]
lrwx------ 1 root root 64 Jun 20 15:39 18 -> socket:[154982]
lrwx------ 1 root root 64 Jun 20 15:39 19 -> socket:[153455]
lrwx------ 1 root root 64 Jun 20 15:38 2 -> /dev/pts/0
lrwx------ 1 root root 64 Jun 20 15:39 20 -> socket:[156950]
lrwx------ 1 root root 64 Jun 20 15:39 21 -> socket:[156951]
lrwx------ 1 root root 64 Jun 20 15:39 22 -> socket:[156952]
lrwx------ 1 root root 64 Jun 20 15:39 23 -> socket:[156953]
lrwx------ 1 root root 64 Jun 20 15:39 24 -> socket:[153456]
lrwx------ 1 root root 64 Jun 20 15:39 25 -> socket:[156954]
lrwx------ 1 root root 64 Jun 20 15:39 26 -> socket:[156955]
lrwx------ 1 root root 64 Jun 20 15:39 27 -> socket:[156956]
lrwx------ 1 root root 64 Jun 20 15:39 28 -> socket:[156957]
lrwx------ 1 root root 64 Jun 20 15:39 29 -> socket:[156958]
lrwx------ 1 root root 64 Jun 20 15:38 3 -> /dev/i2c-1
lrwx------ 1 root root 64 Jun 20 15:39 30 -> socket:[156959]
lrwx------ 1 root root 64 Jun 20 15:39 31 -> socket:[156960]
lrwx------ 1 root root 64 Jun 20 15:39 32 -> socket:[156961]
lrwx------ 1 root root 64 Jun 20 15:39 33 -> socket:[156962]
lrwx------ 1 root root 64 Jun 20 15:39 34 -> socket:[156964]
lrwx------ 1 root root 64 Jun 20 15:39 35 -> socket:[156965]
lrwx------ 1 root root 64 Jun 20 15:39 36 -> socket:[156966]
lrwx------ 1 root root 64 Jun 20 15:39 37 -> socket:[156998]
lrwx------ 1 root root 64 Jun 20 15:39 38 -> socket:[154984]
lrwx------ 1 root root 64 Jun 20 15:39 39 -> socket:[155903]
lrwx------ 1 root root 64 Jun 20 15:38 4 -> anon_inode:[eventpoll]
lrwx------ 1 root root 64 Jun 20 15:39 40 -> socket:[155906]
lrwx------ 1 root root 64 Jun 20 15:39 41 -> socket:[153492]
lrwx------ 1 root root 64 Jun 20 15:39 42 -> socket:[153498]
lrwx------ 1 root root 64 Jun 20 15:39 43 -> socket:[153502]
lrwx------ 1 root root 64 Jun 20 15:39 44 -> socket:[155930]
lrwx------ 1 root root 64 Jun 20 15:39 5 -> socket:[155855]
lrwx------ 1 root root 64 Jun 20 15:39 6 -> socket:[155856]
lrwx------ 1 root root 64 Jun 20 15:38 7 -> socket:[155859]
lrwx------ 1 root root 64 Jun 20 15:39 8 -> socket:[155860]
lrwx------ 1 root root 64 Jun 20 15:39 9 -> socket:[155861]
FrozzenFinger
  • 1,482
  • 2
  • 14
  • 35
  • please see EDIT 0 on my post. – FrozzenFinger Jun 20 '18 at 15:42
  • ...so, you've got a good number of sockets open. Would need to look at the ulimits on your box to know when/where the OS cuts new ones off. Use `lsof` to get a better idea of what those sockets are. – Charles Duffy Jun 20 '18 at 15:44
  • I am sorry but what is ulimits and how i could see when/where OS cuts new sockets off ? (sorry for being a noob) – FrozzenFinger Jun 20 '18 at 15:46
  • Run `ulimit -a` as the same user account running the daemon. Look for "open files". – Charles Duffy Jun 20 '18 at 15:50
  • i am limited at 1024 but how could i reach such a number while i am closing the file i open ? – FrozzenFinger Jun 20 '18 at 15:53
  • Look again at the list from `ls -l` (or, better, the list from `lsof`). It's not the JSON file that's causing your problem, it's all the network sockets. You fill up on network sockets, so there's no FDs left to let you open the JSON file. – Charles Duffy Jun 20 '18 at 15:53
  • Okay i see what you mean so do you think it's possible that my program creates a new socket every time it sends a message to the server ? – FrozzenFinger Jun 20 '18 at 15:56
  • I don't know this library you're using for the `Context`/`Message`/etc tooling, but you might want to look there to figure out how to get *it* to close its file descriptors... assuming that lsof tells you (as I assume it will) that the sockets filling your FD table are connections to 129.6.60.38 – Charles Duffy Jun 20 '18 at 15:56
  • Yes, I do think that's quite possibly what's going on. Maybe you should add that library to your tagging, to get people familiar with it to have their eyes on the question? – Charles Duffy Jun 20 '18 at 15:57
  • okay thanks for your help ! – FrozzenFinger Jun 20 '18 at 15:58
  • 1
    (By the way, does the config file change at runtime? If it doesn't, I'd consider just reading the JSON file once at startup rather than rereading and reparsing it every time you're trying to formulate a new message. Doesn't solve the problem of having your network sockets not get closed, but it's an efficiency improvement if nothing else). – Charles Duffy Jun 20 '18 at 15:59
  • yeah you see when i call the method create message, the first argument depends on the sensor so for now i only have one but i actually will have 10 in a week with different files for every sensor. – FrozzenFinger Jun 20 '18 at 16:01
  • 1
    Still a lot cheaper to read 10 files once at startup rather than 10 files every polling period. If you don't know the names yet at startup time, you can cache them and only do a read when you're asked for a file you haven't seen yet. – Charles Duffy Jun 20 '18 at 16:02
  • 1
    BTW, are you sure that's really asyncio, not aiocoap, creating the network traffic? If not, please update the title and tagging further. – Charles Duffy Jun 20 '18 at 16:05
  • that's right man ahah thank you ! – FrozzenFinger Jun 20 '18 at 16:06
  • ...btw, this smells to me like aiocoap may just be depending on garbage collection to keep up and close the sockets when objects are collected. It's an ugly, awful hack... but does explicitly calling `gc.collect()` inside your loop help? – Charles Duffy Jun 20 '18 at 16:09
  • 1
    @CharlesDuffy: Or the APIs are intended to be [used with `async with`](https://www.python.org/dev/peps/pep-0492/#asynchronous-context-managers-and-async-with) and the OP isn't doing so. – ShadowRanger Jun 20 '18 at 16:18
  • i'll try to ask to the person whom has created this lib thanks a lot for those tracks of research ! – FrozzenFinger Jun 20 '18 at 16:52

1 Answers1

4

Given CoAP's nature of working both as a server and a client, an aiocoap Context is prepared to react to packages even when no request is currently active, and persists until it gets shut down using the .shutdown() coroutine. Depending on the platform, that often means creation of at least a server socket per context, which can lead to file descriptor exhaustion when too many are created.

With very few exceptions, there is no reason why an application should ever create more than one context. As this appears to be a common misunderstanding, the documentation is being updated to make this point more explicit.

chrysn
  • 810
  • 6
  • 19