Python UDP communication using Socket, check data received - python

I'm pretty new to the Python, trying to write a code to receive string from UDP connection, the problem I have now is that I need to receive data from 2 sources, I want the program continue looping if there is no data from either or both of them, but now if there is no data from source 2, it will stop there and wait for the data, how to solve it?
I was thinking about using if statement, but I don't know how to check if the incoming data is empty of not, any ideas will be appreciated!
import socket
UDP_IP1 = socket.gethostname()
UDP_PORT1 = 48901
UDP_IP2 = socket.gethostname()
UDP_PORT2 = 48902
sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock1.bind((UDP_IP1, UDP_PORT1))
sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock2.bind((UDP_IP2, UDP_PORT2))
while True:
if sock1.recv != None:
data1, addr = sock1.recvfrom(1024)
data1_int = int(data1)
print "SensorTag[1] RSSI:", data1_int
if sock2.recv != None:
data2, addr = sock2.recvfrom(1024)
data2_int = int(data2)
print "SensorTag[2] RSSI:", data2_int

If select doesn't work out for you you can always throw them into a thread. You'll just have to be careful about the shared data and place good mutex around them. See threading.Lock for help there.
import socket
import threading
import time
UDP_IP1 = socket.gethostname()
UDP_PORT1 = 48901
UDP_IP2 = socket.gethostname()
UDP_PORT2 = 48902
sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock1.bind((UDP_IP1, UDP_PORT1))
sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock2.bind((UDP_IP2, UDP_PORT2))
def monitor_socket(name, sock):
while True:
sock.recv is not None:
data, addr = sock.recvfrom(1024)
data_int = int(data)
print(name, data_int)
t1 = threading.Thread(target=monitor_socket, args=["SensorTag[1] RSSI:", sock1
t1.daemon = True
t1.start()
t2 = threading.Thread(target=monitor_socket, args=["SensorTag[2] RSSI:", sock2])
t2.daemon = True
t2.start()
while True:
# We don't want to while 1 the entire time we're waiting on other threads
time.sleep(1)
Note this wasn't tested due not having two UPD sources running.

Related

how to do something like streams inside a port (Python socket)

there is such a code:
server:
import socket
from threading import Thread
from time import sleep
sock = socket.socket()
sock.bind(('', 1337))
sock.listen(1)
conn, addr = sock.accept()
def func1():
while True:
conn.send("1".encode("utf-8"))
sleep(0.5)
def func2():
while True:
conn.send("2".encode("utf-8"))
sleep(0.5)
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
client:
import socket
from threading import Thread
from time import sleep
sock = socket.socket()
sock.connect(('localhost', 1337))
def func1():
while True:
data = sock.recv(1024).decode("utf-8")
if data != "1":
print("the package did not arrive properly")
else:
print("package arrived ok")
def func2():
while True:
data = sock.recv(1024).decode("utf-8")
if data != "2":
print("the package did not arrive properly")
else:
print("package arrived ok")
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
I need to make sure that the packet sent by function1 comes to function1, and the packet of function2 comes to function2, but this code does not work correctly, and packets from function1 often end up in function2 and vice versa
I feel like you are approaching this from the wrong direction. You do not need multiple threads in the server or client. If you have multiple threads that is fine, but that's really not relevant for the problem you are having.
You are trying to multiplex multiple different types of messages over a single socket connections. In other words, you need a communication protocol.
On top of that, you have another problem that you do not appear to be aware of yet. Sockets are streams of bytes, in particular, they are not messages. If you send multiple messages in quick succession, they might be truncated or combined in the receiver.
If you send the following packages:
1
2
1
1
2
They could be received as follows:
12
112
Then your receiver will be very confused. Again, this problem can be resolved with a communication protocol.
There are many different ways to implement a communication protocol. The simplest that I can think of is to use JSON:
# sender.py
import socket
import time
import json
sock = socket.socket()
# https://stackoverflow.com/a/6380198/8746648
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', 1337))
sock.listen(1)
conn, addr = sock.accept()
while True:
# If necessary, you can make these calls from different threads.
# Notice, that we append a newline at the end, this is needed for 'readline' to work properly.
conn.send(json.dumps({ "type": 1, "payload": 42 }).encode("utf-8") + b"\n")
time.sleep(0.5)
conn.send(json.dumps({ "type": 2, "payload": "can-be-anything" }).encode("utf-8") + b"\n")
time.sleep(0.5)
# receiver.py
import socket
import json
sock = socket.socket()
sock.connect(('localhost', 1337))
# We know, that the messages themselves do not contain newline characters
# and the server sends a newline after each message, therefore, this will receive a complete message.
sock_file = sock.makefile()
while line := sock_file.readline():
object_ = json.loads(line)
# If you want to you can handle the messages in different threads.
# This could be done by setting up a queue that is consumed by working threads.
if object_["type"] == 1:
print(f"received(1): {object}")
elif object_["type"] == 2:
print(f"received(2): {object}")
If you are willing you could use multiple ports
<Client>
import socket
from threading import Thread
from time import sleep
def func1():
sock = socket.socket()
sock.connect(('localhost', 1338))
while True:
data = sock.recv(1024).decode("utf-8")
if data != "1":
print("the package did not arrive properly")
else:
print("package arrived ok")
def func2():
sock = socket.socket()
sock.connect(('localhost', 1337))
while True:
data = sock.recv(1024).decode("utf-8")
if data != "2":
print("the package did not arrive properly")
else:
print("package arrived ok")
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
<Server>
import socket
from threading import Thread
from time import sleep
def func1():
sock = socket.socket()
sock.bind(('', 1338))
sock.listen(1)
conn, addr = sock.accept()
while True:
conn.send("1".encode("utf-8"))
sleep(0.5)
def func2():
sock = socket.socket()
sock.bind(('', 1337))
sock.listen(1)
conn, addr = sock.accept()
while True:
conn.send("2".encode("utf-8"))
sleep(0.5)
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()

How to see that we've reached the end of the data for a socket connection?

Is there something the client needs to do in order to flag that "This is the end?"
For example, I have the following server running:
import socket, sys
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 5500))
s.listen(1)
conn, addr = s.accept()
print('Connected by', addr)
data = b''
while True:
data_chunk = conn.recv(10)
data += data_chunk
if not data: break
# How do I get here so I can echo the message *at the end* ?
# conn.send(b'Done. What you sent was: %s' % data)
And I have the following client code:
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('sandbox2.myip.com', 5500))
client_socket.send(b'select * from table')
# Now, what to do so that I can get the final message from he server?
When I do the connection though, this is what it shows:
sampleDB$ python listener.py
Connected by ('99.51.149.29', 63352)
I can confirm that the data data_chunks are being received, but then it just seems to hang at this part right here:
data_chunk = conn.recv(10)
Is there something I need to do in the client (or the server?) to flag that "This is the end of the transmission, so conn.recv() doesn't just hang indefinitely?
Here's a complete example of a socket based client/server protocol that implements the strategy described in my comment:
import socket
import threading
from struct import pack, unpack
HOST = 'localhost'
PORT = 7070
FORMAT = ('!Q', 8)
MSG = '''The Owl and the Pussy-cat went to sea
In a beautiful pea-green boat,
They took some honey, and plenty of money,
Wrapped up in a five-pound note.
The Owl looked up to the stars above,
And sang to a small guitar,
"O lovely Pussy! O Pussy, my love,
What a beautiful Pussy you are,
You are,
You are!
What a beautiful Pussy you are!"'''
def sendbuffer(s, b):
buffer = pack(FORMAT[0], len(b)) + b
offset = 0
while offset < len(buffer):
offset += s.send(buffer[offset:])
def recvbuffer(s):
p = s.recv(FORMAT[1], socket.MSG_WAITALL)
n = unpack(FORMAT[0], p)[0]
return None if n == 0 else s.recv(n, socket.MSG_WAITALL)
def server():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, _ = s.accept()
with conn:
while (data := recvbuffer(conn)):
sendbuffer(conn, data)
def client(msg):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
sendbuffer(s, msg.encode())
data = recvbuffer(s)
print(data.decode())
sendbuffer(s, b'') # kill switch
def main():
threading.Thread(target=server).start()
client(MSG)
if __name__ == '__main__':
main()

How can I return socket created by function and pass it to another?

I would like to define function that creates socket, binds socket to specific address and port, get data from source(incessantly) and then return this socket so I could use it in other function. Is it possible? If so, how can I do that?
I would like to multithread socket_analyser, does it imply multithreading socket_receiver also?
The problem is that after invoking socket_creator, the function doesn't return sock. When I try to pass it to socket_receiver in socket_analyser it underline parameter sock saying it's not defined.
I also tried to define testsocket = sock just after socket_creator(MCAST_GRP[0],MCAST_PORT) to pass it to socket_receiver(testsock, BUFFER_UDP) however - the same result.
import socket
import struct
import time
import threading
MCAST_GRP = ['239.0.1.104','239.0.1.105']
MCAST_PORT = 12345
BUFFER_UDP = 2048
def socket_creator(multicast_group, multicast_port):
MCAST_GRP = multicast_group
MCAST_PORT = multicast_port
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
return sock
#testsocket = sock
def socket_receiver(sockett, bufferUDP):
BUFFER_UDP = bufferUDP
sock_rcv = sockett
for x in range(10):
data, address = sock_rcv.recvfrom(BUFFER_UDP)
totalSize += len(data)
return totalSize
def socket_analyser(multicast_group, multicast_port, totalSize):
print("_____.:| Starting analysis! |:._____\n")
print("͞◌͞◌͞◌͞◌͞.:| IP: {} PORT: {} |:.͞◌͞◌͞◌͞͞◌͞◌".format(multicast_group,multicast_port))
socket_analyser(sock, BUFFER_UDP)
print(totalSize)
totalSize = 0
socket_creator(MCAST_GRP[0],MCAST_PORT)
socket_creator(MCAST_GRP[1],MCAST_PORT)
t1 = threading.Thread(target=socket_analyser, args=(MCAST_GRP[0],MCAST_PORT,BUFFER_UDP, sock))
t2 = threading.Thread(target=socket_analyser, args=(MCAST_GRP[1],MCAST_PORT,BUFFER_UDP, sock))
t1.start()
t2.start()
t1.join()
t2.join()
print('End of test')
time.sleep(5)
Thank you in advance for anything bringing me closer to the solution
I am seeing a couple of logical issues in the code
sock object scope is only inside socket_creator so it would not be available outside unless you receive the return result into another variable
You are passing an undefined variable sock to the analyzer method
You are recursively calling socket_analyser method inside socket_analyser method
I just modified a few things to fix
def socket_analyser(BUFFER_UDP, sock):
socket_receiver(sock, BUFFER_UDP)
print(BUFFER_UDP)
sock1 = socket_creator(MCAST_GRP[0],MCAST_PORT)
sock2 = socket_creator(MCAST_GRP[1],MCAST_PORT)
t1 = threading.Thread(target=socket_analyser, args=(BUFFER_UDP, sock1))
t2 = threading.Thread(target=socket_analyser, args=(BUFFER_UDP, sock2))

how can we use both tcpSerSock.listen(0) and tcpSerSock.send(str.encode(message)) at the same time

my raspberry pi is the server and Im trying to send continuous message from rpi to android while recieving a command from client (android app),i really dont know if this is possible and how to do it is out of my reach and it is not a feedback message here is my code hope you will help me thank you.
import apptopi
from socket import *
from time import ctime
from nanpy import (ArduinoApi, SerialManager)
apptopi.setup()
connection = SerialManager()
a = ArduinoApi(connection = connection)
ctrCmd = ['Up','Down','Left','Right','Stop','Connect']
add = 0
add += 1
a = str(add) //**this is a sample that i want to send continously
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(0)
tcpSerSock.send(str.encode(a)) <== i really don't know how to send
continuously
while True:
print 'Waiting for connection'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from :', addr
try:
while True:
data = ''
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
if data == ctrCmd[0]:
apptopi.forw()
print 'forward'
if data == ctrCmd[1]:
apptopi.back()
print 'backward'
if data == ctrCmd[2]:
apptopi.left()
print 'leftturn'
if data == ctrCmd[3]:
apptopi.right()
print 'rightturn'
if data == ctrCmd[4]:
apptopi.stp()
print 'stop'
except KeyboardInterrupt:
apptopi.close()
GPIO.cleanup()
tcpSerSock.close();
OK one approach is to use the select() function for this. There is information in the documentation about its operation.
As an example I've made a modified version of your program (see below). I don't have a raspberry pi, so that part of the code is commented out, but you can replace it as needed.
The example uses the timeout feature of select() to send "continuous" messages to clients whilst also monitoring them for incoming messages. You can adjust the message contents and timeout to whatever works for you. NB you may also need to respond to client messages, as this code only sends data to clients after a timeout. Make whatever changes you need.
import sys
import socket
import select
ctrCmd = ['Up','Down','Left','Right','Stop','Connect']
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(1)
print 'Waiting for connection'
sendInterval = 1.0 # interval(sec) for sending messages to connected clients
rxset = [tcpSerSock]
txset = []
while 1:
rxfds, txfds, exfds = select.select(rxset, txset, rxset, sendInterval)
if rxfds:
for sock in rxfds:
if sock is tcpSerSock:
# a client is connecting
tcpCliSock, addr = tcpSerSock.accept()
tcpCliSock.setblocking(0)
rxset.append(tcpCliSock)
print '...connected from :', addr
else:
# a client socket has data or has closed the connection
try:
data = sock.recv(BUFSIZE)
if not data:
print "...connection closed by remote end"
rxset.remove(sock)
sock.close()
else:
if data == ctrCmd[0]:
#apptopi.forw()
print 'forward'
if data == ctrCmd[1]:
#apptopi.back()
print 'backward'
if data == ctrCmd[2]:
#apptopi.left()
print 'leftturn'
if data == ctrCmd[3]:
#apptopi.right()
print 'rightturn'
if data == ctrCmd[4]:
#apptopi.stp()
print 'stop'
except:
print "...connection closed by remote end"
rxset.remove(sock)
sock.close()
else:
# timeout - send data to any active client
for sock in rxset:
if sock is not tcpSerSock:
sock.send("Hello!\n")
The simple client program I used to test this is here:
import sys
import socket
import time
ctrCmd = ['Up','Down','Left','Right','Stop','Connect']
HOST = '127.0.0.1'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)
time.sleep(1)
for i in range(len(ctrCmd)):
tcpCliSock.send(ctrCmd[i])
time.sleep(1)
data = tcpCliSock.recv(BUFSIZE)
print data
tcpCliSock.close()
Hope this helps, best of luck.

Python 3 Threading Using Two Ports

i am working on a basic python program to get used to threading and networking and i have become a little unstuck at one section of my code.
what i have is:
#make a socket and loop to obtain connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ads = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1" , 4000))
ads.bind(("127.0.0.1" , 4001))
s.listen(10)
ads.listen(1)
socks = [s,ads]
connections = [] # list of connections
while True:
if ads:
(c,a) = ads.accept()
t = threading.Thread(target = admin_client, args = ())
t.start()
elif :
(c,a) = s.accept()
connections.append(c)
t = threading.Thread(target = handle_client, args = (c,a))
t.start()
What i was hoping to happen was when the ads port was accessed it would assign it to the admin_client method which it seems to perform but it will just do nothing if anything connects on the s port.
Does anyone have a solution for this so both clients will connect with no issues?
if ads: is always True. You need to use select. Since if ads: is always True you drop into (c,a) = ads.accept() which waits for someone to connect to the ads port.
Something like (untested):
r,w,x = select.select(socks,[],[])
if ads in r:
...
elif s in r:
...

Categories

Resources