<div dir="auto">Perhaps using tcp (connection oriented) sockets, so you don't have to search for the IP of the other end? </div><div class="gmail_extra"><br><div class="gmail_quote">On Feb 3, 2017 3:40 AM, "Alex Carver" <<a href="mailto:agcarver%2Bale@acarver.net">agcarver+ale@acarver.net</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I've been trying to figure out a method of tracking some sockets but I<br>
keep running into roadblocks.<br>
<br>
I've got a small daemon python script that runs a thread to accept<br>
connections from remote devices. All the basic stuff is working so no<br>
problems there. What I'm trying to do is make an asynchronous queue for<br>
the thread so I can send data back towards those devices.<br>
<br>
The queue idea was to put the device IP address and the data to send<br>
into the queue (all IPs are static and known). The daemon thread loops<br>
continuously looking for status updates from the remote devices (via<br>
select() ). At the end of the loop, it would check the queue for new<br>
items and send the data to the appropriate device.<br>
<br>
I currently keep a list of the socket objects that get created for every<br>
new connection. This list gets fed into select() during each loop to<br>
tell me where there's data waiting to be received from some device. The<br>
devices don't send regular updates on a rapid basis. Instead they<br>
maintain an open connection and send updates once every couple minutes<br>
unless some event occurs and then they send an immediate update.<br>
<br>
Problem: I don't want to wait for one of the devices to send its message<br>
so I can send the data back. I want to send as soon as the data is in<br>
the queue.<br>
<br>
First brute force solution is to loop through all the available sockets,<br>
check to see if the remote IP matches the one in the queue, then send<br>
data to it. Works but can get bogged down as it does a getpeer() (to<br>
get the remote IP) on each socket until it finds a match.<br>
<br>
I didn't like that idea so I thought about two related lists. One was<br>
keyed on the IP and the other keyed on the socket. The IP key works<br>
fine but you can't use an object as a key in Python. The reason for the<br>
second list keyed on socket is to avoid having to run through the IP<br>
keyed array looking for a matching value when trying to purge a dead<br>
socket (i.e. looping through the list of socket objects that select()<br>
returned, if one is dead you can't do a getpeer() on it so go to the<br>
second list, search for the socket ID and get its IP)<br>
<br>
Ok, so next idea was to use the file descriptor of the socket to get<br>
around the key problem. I thought that was going to work until I ran<br>
into the hiccup of the socket possibly disappearing (timed out<br>
connection, device powers off, etc.) When the socket closes for whatever<br>
reason, the file descriptor goes away although the object persists until<br>
it's garbage collected after explicitly close()d. If the file<br>
descriptor vanishes, I can't use it to purge the lists.<br>
<br>
So I'm trying to figure out if there's a more persistent identifier<br>
available that can be used as a key and will persist through a socket<br>
termination and can also be used to reference the socket it came from<br>
<br>
<br>
<br>
The gist of the daemon (this runs in a loop) in rough Python (some<br>
pseduo-Python for brevity):<br>
<br>
read,write,error = select(socketlist, [], [], 0) # no blocking<br>
<br>
for s in read:<br>
if s == the_server_socket:<br>
client, address = s.accept()<br>
socketlist.append(client)<br>
#right here I would want to add:<br>
client_track_list_by_ip[<wbr>address] = client.identifier<br>
client_track_list_by_<wbr>identifier[client.identifier] = ip<br>
<br>
else:<br>
#this was a client device, do things<br>
<br>
<br>
#this bit of code runs in various places<br>
#the idea is to remove the socket from the<br>
#socketlist if it's dead<br>
<br>
(if the socket is dead or caused an error):<br>
socketlist.remove(s)<br>
#here I would attempt to purge the two tracking lists<br>
#get peer won't work here because the socket<br>
#isn't connected, go find it in the other list<br>
ip = client_track_list_by_<wbr>identifier[s.identifier]<br>
del client_track_list_by_ip[ip]<br>
del client_track_list_by_<wbr>identifier[s.identifier]<br>
s.close()<br>
<br>
<br>
#then the queue handling:<br>
while ( queue is not empty ):<br>
queue_item = getfromqueue()<br>
<br>
send_to_socket(client_track_<wbr>list_by_ip[queue_item.ip], queue_item.data)<br>
<br>
______________________________<wbr>_________________<br>
Ale mailing list<br>
<a href="mailto:Ale@ale.org">Ale@ale.org</a><br>
<a href="http://mail.ale.org/mailman/listinfo/ale" rel="noreferrer" target="_blank">http://mail.ale.org/mailman/<wbr>listinfo/ale</a><br>
See JOBS, ANNOUNCE and SCHOOLS lists at<br>
<a href="http://mail.ale.org/mailman/listinfo" rel="noreferrer" target="_blank">http://mail.ale.org/mailman/<wbr>listinfo</a><br>
</blockquote></div></div>