python check socket receive within other loop -- non-blocking? - python

I know the code to wait for socket in a loop like this.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
data, addr = s.recvfrom(1024)
data = data.decode('utf-8')
print("Message from: " + str(addr))
print("From connected user: " + data)
com = data
data = data.upper()
data = "Message Received: " + data
however, I want to use this function in another main loop that refreshes every second. When this get called it freezes until meeting any msg.
Is there any way that I can "check msg" on off, and integrate this in the main loop refreshes every second?
Many thanks.

You can use select.select to poll for readiness to receive a message:
import socket
import select
s = socket.socket(type=socket.SOCK_DGRAM)
s.bind(('', 5000))
while True:
r, _, _ = select.select([s], [], [], 1.0)
if r: # r will contain s if a message is ready
data, addr = s.recvfrom(1024)
data = data.decode('utf-8')
print(f'\n{addr}: {data}')
else:
print('.', end='', flush=True) # show activity

Related

How to break while loop when a new message arrives?

I have used Python socket in ESP as a server and Laptop as a client. I customized the socket codes from this site. When I send the loop as the client input, I enter a loop on the server. I don't know how the while loop is broken when I send a word other than loop, For example "Hello".
server.py:
import socket
host = ''
port = 5560
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind comlete.")
return s
def setupConnection():
s.listen(1)
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def Hello_():
print('Hello')
def Loop_():
while True:
print('yes')
def dataTransfer(conn):
while True:
data = conn.recv(1024)
data = data.decode('utf-8')
dataMessage = data.split(' ', 1)
command = dataMessage[0]
if command == 'loop':
Loop_()
if command == 'Hello':
Hello_()
else:
print("X")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
break
client.py
import socket
host = '192.168.56.1'
port = 5560
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
while True:
command = input("Enter your command: ")
s.send(str.encode(command))
s.close()
I know your time is valuable and I appreciate your attention for spending time for help me.
If you want the Loop_() method to return when more data is received on the socket, you can modify the method so that it calls select() to poll the socket to see if more data has arrived, as shown below. (Note that I've added a conn argument to the Loop_() method so I can pass in the socket to check it)
import select
[...]
def Loop_(conn):
while True:
print('yes')
inReady, outReady, exReady = select.select([conn], [], [], 0.0)
if (conn in inReady):
print('more data has arrived at the TCP socket, returning from Loop_()')
break
def dataTransfer(conn):
while True:
data = conn.recv(1024)
data = data.decode('utf-8')
dataMessage = data.split(' ', 1)
command = dataMessage[0]
if command == 'loop':
Loop_(conn)
if command == 'Hello':
Hello_()
else:
print("X")
conn.close()

How can I monitor client side inputs and send input requests from server every 5 seconds if no input is received?

I want to set up tcp server and client where server monitors client input and sends a request every 3 seconds if no input is received. Then client replies with its time. This goes on in an infinite loop. Also, they both have an option to exit the infinite loop. I don't know how to add the exit functionality as send(), recv() and input() block the code execution.
I have tried using select with 3 second timeout, it didn't work. I have tried threading but it stops after first user input until the next user input. I want it to go infinitely unless user wants to exit.
Infinite loop for communication:
client side:
while True:
data = ClientSocket.recv(1024).decode()
print("From Server: " + str(data))
# clear string
data = ''
data = 'Random Number: ' + str(random.randint(1, 101))
current_time = datetime.now()
required_format = (current_time.strftime("Date: %Y-%m-%d\tTime: %H:%M:%S.%f")[:-3])
data = data + "\t" + required_format + '\n'
ClientSocket.send(data.encode())
print("Sending: " + str(data))
data = ''
Server Side:
while True:
data = ''
data = 'Please enter a response.'
print("Sending: " + str(data))
ClientSocket.send(data.encode())
# clear string
data = ''
data = ClientSocket.recv(1024).decode()
print("From Client: " + str(data))
Select function that i tried:
readlist = [ClientSocket]
incoming = select.select(readlist, [], [], 3)
if incoming:
#perform a chat function here
else:
#use the code mentioned above for automated messages
This is the threading feature that I tried:
Python 3 Timed Input
How can I restrict time for recv(), send() and input() while sending and receiving message request and acknowledgements?
Please let me know if you would like to see the full code.
Something like this should work for you
server.py
inputs = [server]
outputs = []
messages = {}
try:
while inputs:
readable, writable, error = select.select(inputs, outputs, [])
for sock in readable:
if sock is server:
client, _ = sock.accept()
inputs.append(client)
messages[client] = Queue()
else:
data = sock.recv(1024).decode()
if data and data != 'exit\n':
print(data)
messages[sock].put(data)
if sock not in outputs:
outputs.append(sock)
else:
print('Client disconnected')
sock.close()
inputs.remove(sock)
for sock in outputs:
try:
msg = messages[sock].get_nowait()
sock.send(msg.upper().encode())
except Empty:
sleep(3)
sock.send(b'No data recieved')
outputs.remove(sock)
except KeyboardInterrupt:
server.close()
client.py
inputs = [sock, sys.stdin]
while inputs:
readable, _, _ = select.select(inputs, [], [])
for s in readable:
if s is sock:
data = sock.recv(1024).decode()
if data:
if data.lower() != 'exit':
print('{}'.format(data))
sys.stdout.write('You: ')
sys.stdout.flush()
else:
exiting('Server')
else:
exiting('Server')
else:
msg = sys.stdin.readline()
sock.send(msg.encode())
sys.stdout.write('You: ')

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.

How can I make my connection counter go down

Hello I've been trying to make my python sock server connection counter to go down
but I can't figure out how I can do this
def client_thread(conn):
while True:
conn.send("Command: ")
data = conn.recv(1024)
if not data:
break
reply = "" + data
conn.sendall("\r")
if data == "!* Connections":
conn.sendall("[+] Clients Connected: %s \r\n" % (clients))
conn.close()
while True:
conn, addr = sock.accept()
clients = clients + 1
start_new_thread(client_thread, (conn,))
sock.close()
I needn't show you all of the code because its irrelevant to this issue,
I have provided the code that make's the counter go up when a new connection connects, but as said before I don't know how to make it go down when a connection leaves.
When trying to find solutions online there show's nothing that can help my issue
Here is a small sample how to realize a client counter with the select.select function. I actually took it from the great article select – Wait for I/O Efficiently on pymotw.com and added a client counter. Basically you look for readable sockets and try to receive data from them. If a socket returns nothing it means it has been closed and can be removed from the client list.
import queue
import socket
import select
clients = 0
sock = socket.socket()
sock.bind(('localhost', 5000))
sock.listen(5)
inputs = [sock]
outputs = []
msg_queues = {}
while inputs:
readable, writable, exceptional = select.select(
inputs, outputs, msg_queues)
for s in readable:
if s is sock:
conn, addr = sock.accept()
print('new connection from ', addr)
conn.setblocking(0)
inputs.append(conn)
msg_queues[conn] = queue.Queue()
# increment client counter
clients += 1
print('Clients: ', clients)
else:
# try to receive some data
data = s.recv(1024)
if data:
# if data available print it
print('Received {} from {}'.format(data, s.getpeername()))
msg_queues[s].put(data)
# add output channel for response
if s not in outputs:
outputs.append(s)
else:
# empty data will be interpreted as closed connection
print('Closing connection to ', s.getpeername())
# stop listening for input on the connection
if s in outputs:
outputs.remove(s)
# remove from inputs
inputs.remove(s)
s.close()
# decrement client counter
clients -= 1
del msg_queues[s]
print('Clients: ', clients)

the code stuck after receiving one byte from the socket ?

In the code shown below I am using the blocking call to receive 50 bytes of data from socket and echo it back.But what is happening is that the code stuck after receiving one byte.In the telnet running on another command prompt the connection still shows as connected. What might be missing from this ?
import socket
import sys
host = ''
port = 8888
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
print 'Socket Bind Complete'
s.listen(10)
print 'Now Listening'
while 1:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
The problem is that you're accepting a new connection each time through the loop, and only receiving from that connection once. The next time through the loop, your forget about that connection and accept a new one, which blocks until someone else connects.
If you just want to handle a single connection and quit, just move the accept outside the loop:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle one connection at a time, but then wait for a new connection after you finish with the first, add an outer loop.
while True:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle more than one connection at a time, as most servers do, you need some sort of asynchronous mechanism—select and nonblocking sockets, gevent, threads, whatever. For example:
def handle_client(conn, addr):
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
client_threads = []
try:
while True:
conn, adr = s.accept()
client_thread = threading.Thread(target=handle_client, args=[conn, addr])
client_thread.start()
client_threads.append(client_thread)
finally:
s.close()
for client_thread in client_threads:
client_thread.join()
In any of these designs, you're probably better off using a with statement instead of explicit close calls and/or try/finally.

Categories

Resources