I was a socket TCP server in python using asyncore. My handle_read function is:
def handle_read(self):
data = self.recv(50)
'''interpretar os comandos:
operação: Ligar/Desligar Bomba, Ligar/Desligar Aquecedor, Alterar velocidade da bomba
Modo: trocar de modo automático para remoto
Armazenamento: ativar ou desativar o armazenamento de dados para o trend e
também apagar dados
'''
if len(data) < 2: #comandos digitais
try:
process_commands(data)
except Exception as err:
print(str(err))
else: #comando analogico
try:
ld = json.loads(data.decode('utf-8'))
bytescommand = pack('f',ld['pump_speed'])
bus.write_block_data(arduinoAddress,53,list(bytescommand))
except Exception as err:
print(str(err))
finally:
pass
Look, i test the data received to execute functions. But when a client disconnect, the program returns:
"char format requires a bytes object of lenght 1"
This indicates that handle_read function executes when client disconnect.
It's normal? How i proccess the situation?
Thanks a lot!
That is a normal call. When the peer closes its socket (or simply shutdowns it with SH_WR) a read call returns immediately with 0 bytes.
So your handle_read should be prepared for that end of file on the socket:
def handle_read(self):
...
if len(data) == 0: # EOF on input socket
pass # or add disconnection processing...
elif len(data) < 2: #comandos digitais
...
Related
I'm trying to make a connection tester with python and made this function:
import socket as skt
import sys
def main():
try:
s = skt.socket(skt.AF_INET, skt.SOCK_STREAM, 0)
except skt.error as e:
print('A conexão falhou! :(')
print(f'Erro {e}.')
sys.exit()
print("Socket criado com sucesso!")
HostTarget = input('Digite o Host ou IP a ser conectado: ')
DoorTarget = (input('Digite a porta a ser conetcada: '))
try:
s.connect:((HostTarget, int(DoorTarget)))
print(f'Cliente conectado com sucesso no Host: {HostTarget} através da porta: {DoorTarget}.')
s.shutdown(2)
except skt.error as e:
print(f'Não foi possível se conectar ao Host: {HostTarget} através da porta: {DoorTarget}.')
print(f'Erro: {e}')
sys.exit()
if __name__ == "__main__":
main()
But when I run the test, I get the following error:
Erro: [Errno 107] Transport endpoint is not connected
An exception has occurred, use %tb to see the full traceback.
How do I flush a socket in python3?
I'm looking to do something like this
def clear_buffer(sock):
try:
while sock.recv(1024): pass
except:
pass
or
def clear_buffer(sock):
while True:
data = sock.recv(1024)
if not data:
break
After attempting to run these two functions neither seem to break the while loop and/or flush out the socket from incoming data. How do I conditionally do something when the socket has stopped receiving data?
while run_network:
recv = True
data = b''
try:
while recv:
try:
packet = socket.recv(10240)
if packet:
data += packet
else:
recv = False
try:
pickle.loads(data)
recv = False
except:
recv = True
except ConnectionResetError:
print(f"{client} has disconnected........")
break
except ConnectionError:
**strong text**
print(f"{client}has a Connection Error.....")
break
I found some code here for a project at : https://picamera.readthedocs.io/en/release-1.13/recipes2.html#rapid-capture-and-streaming section 4.9
I successfully make it work but when i tried to put the serveur on the raspberry py instead of the client, i would not work.
EDIT:
EDIT:
I found the answer : On the server the file needs to be open in write (wb) and on the client it needs to be open in read (rb)
However, we get 7 secondes of latency beteen the server and the client, Do you know how i could lower it ?
LE SERVEUR
# -*-coding:utf-8 -*
import io
import socket
import struct
from PIL import Image, ImageTk
from threading import Thread
import time
class ControleurClientVideo():
def __init__(self, controleur_client):
self.adresse='0.0.0.0'
self.port=8000
self._client_socket = socket.socket()
self._connection = None
self._thread = None
self._stop = False
def connection_raspberry(self):
self._thread = Thread(target=self._connection_avec_raspberry)
self._thread.start()
def _connection_avec_raspberry(self):
try:
self._client_socket.connect((self.adresse, self.port))
self._connection = self._client_socket.makefile('wb')
self._connection_active=True
print("Connection avec le serveur etabli")
time.sleep(2)
self._recevoir_flux_image()
except Exception as e:
print(e)
def _recevoir_flux_image(self):
try:
while not (self._stop):
# Read the length of the image as a 32-bit unsigned int. If the
# length is zero, quit the loop
image_len = struct.unpack('<L',
self._connection.read(struct.calcsize('<L')))[0]
if not image_len:
self.connection_perdu = True
break
# Construct a stream to hold the image data and read the image
# data from the connection
image_stream = io.BytesIO()
image_stream.write(self._connection.read(image_len))
# Rewind the stream, open it as an image with PIL and do some
image_stream.seek(0)
image_pill = Image.open(image_stream)
image_pill = image_pill.resize((320, 240), Image.ANTIALIAS)
image_tk = ImageTk.PhotoImage(image_pill)
print(image_tk)
self.controleur_client.changer_image(image_tk)
finally:
self.fermer_connection()
def fermer_connection(self):
self._stop = True
time.sleep(0.5)
if not (self._connection == None):
self._connection.close()
self._connection = None
self._client_socket.close()
self._client_socket=None
self._thread = None
print("Connection avec le serveur fermer")
LE CLIENT
# -*-coding:utf-8 -*
import io
import socket
import struct
import time
import picamera
from threading import Thread
class ControleurStreamingVideo():
def __init__(self):
self.adresse='0.0.0.0'
self.port=8000
self._serveur_socket = socket.socket()
self._serveur_socket.bind((self.adresse, self.port))
self._connection = None
self._thread=None
def ouvrir_serveur(self):
self._thread = Thread(target=self._connection_avec_client)
self._thread.start()
def _connection_avec_client(self):
try:
print("Serveur en attente d'une connection...")
self._serveur_socket.listen(5)
self._connection = self._serveur_socket.accept()[0].makefile('rb')
print("Connection réussi, début de la vidéo")
except Exception as e:
repr(e)
finally:
self._envoit_image()
self._serveur_socket.close()
def _envoit_image(self):
try:
self.output = SplitFrames(self._connection)
with picamera.PiCamera(resolution='VGA', framerate=30) as camera:
time.sleep(1) #warmup la caméra
camera.start_recording(self.output, format='mjpeg')
camera.wait_recording(30)
camera.stop_recording()
self._serveur_socket.close()
except Exception as e:
print(e)
class SplitFrames(object):
def __init__(self, connection):
self.connection = connection
self.stream = io.BytesIO()
def write(self, buf):
if buf.startswith(b'\xff\xd8'):
# Start of new frame; send the old one's length
# then the data
size = self.stream.tell()
if size > 0:
self.connection.write(struct.pack('<L', size))
self.connection.flush()
self.stream.seek(0)
self.connection.write(self.stream.read(size))
self.stream.seek(0)
self.stream.write(buf)
When i run the program it says only write for error. I found out that the problem come from the method write in SplitFrames. Any idea on what is causing this
SERVEUR:
Serveur en attente d'une connection...
Connection réussi, début de la vidéo
write
CLIENT:
Connection avec le serveur etabli
Connection avec le serveur fermer
read
EDIT:
I found the answer : On the server the file needs to be open in write (wb) and on the client it needs to be open in read (rb)
However, we get 7 secondes of latency beteen the server and the client, Do you know how i could lower it ?
My development environment is macos mojave. I encapsulate selectors.DefaultSelector() with a class named Server. This class is used to handle clients concurrent requests. If the class inherits from multiprocessing.Process and tries to run error in a child process,the following error occurs like this:
Self.sel1.register(self.listenSock, selectors.EVENT_READ, data=None)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/selectors.py", line 522, in register
Self._selector.control([kev], 0, 0)
OSError: [Errno 9] Bad file descriptor
However it run work in main process (doesn't inherit multiprocessing.Process),So how can I solve this problem?
import types
import time
import multiprocessing as mp
Socket=socket.socket
request_que=mp.Queue()
def finditer(data,sub:str,count:int):
#Continuous traversal to find the specified character
pos=0
while count>0:
i=data[pos+1:].find(sub)
if i>=0:
pos+=(i+1)
count-=1
#end-while
return pos
#end-def
def get_host_info(req:bytes):
'''
Get information about the requesting server from the Socket
request byte stream
'''
host,port,url,is_https='','','',False
def extract_ip_port(req,method=b'GET'):
ed=req.index(b' HTTP/1.1')
url=req[len(method)+1:ed]
st=finditer(url,b'/',2)+1
ed=finditer(url,b'/',3)
server=url[st:ed]
pos=server.rfind(b':')
if pos>0:
port=int(server[pos+1:])
host=server[:pos]
if host.startswith(b'['): #ipv6
host=host[1:-1]
else:
port=80
host=server
#end-if
return host,port,url
#end-def
if req.startswith(b'GET'):
host,port,url=extract_ip_port(req)
elif req.startswith(b'POST'):
host,port,url=extract_ip_port(req,method=b'POST')
elif req.startswith(b'CONNECT'):
ed=req.index(b' HTTP/1.1')
req=req[8:ed]
req=req.split(b':')
host,port=req[0],req[1]
is_https=True
return host,port,url,is_https
#end-def
class Server(mp.Process):
def __init__(self,locIP,locPort,reqQue):
super(Server, self).__init__()
self.locIP=locIP
self.locPort=locPort
self.listenSock=None
self.reqQue=reqQue
self.sel1=selectors.DefaultSelector()
def accept_wrapper(self,sock: socket.socket):
'''
Since the listened socket is registered to selectors.EVENT_READ, it can now be read, and immediately call sock.accept and conn.setblocking(False)
to get the socket into non-blocking mode.
'''
conn, addr = sock.accept()
print('accepted connection from ', addr)
conn.setblocking(False)
conn.settimeout(6)
#Dynamically create a temporary object class, data is used to track
#the data sent and received by each socket object
data = types.SimpleNamespace(addr=addr, inb=b'', outb=b'')
events = selectors.EVENT_READ | selectors.EVENT_WRITE
self.sel1.register(conn, events, data=data)
# end-def
def run(self):
try:
self.listenSock =Socket(socket.AF_INET, socket.SOCK_STREAM)
self.listenSock.setblocking(False)
self.listenSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.listenSock.bind((self.locIP,self.locPort))
self.listenSock.listen(5)
print(f'Server Process:{os.getpid()}')
print(f'Server is running & listen on {self.locIP}:{self.locPort}')
#Selector.register() Registers socket monitoring for the event you
#are interested in using selector.select() . For listening sockets,
#we want to use selectors.EVENT_READ
self.sel1.register(self.listenSock, selectors.EVENT_READ, data=None)
except BlockingIOError as e:
raise e
except OSError as e:
raise e
try:
while True:
events = self.sel1.select(timeout=None)
for key, mask in events:
# If None indicates a socket for listening
if key.data is None:
self.accept_wrapper(key.fileobj)
else:
self.service_connection(key, mask)
# end-for
# end-while
except KeyboardInterrupt:
print('keyboard interrupt by user,server exit')
except OSError as e:
print(e)
finally:
self.sel1.close()
# end-def
def service_connection(self,key, mask):
sock = key.fileobj
data = key.data
if mask & selectors.EVENT_READ:
request = sock.recv(MAX_RECV_BUF)
if request:
data.inb += request
host,port,url,is_https=get_host_info(data.inb)
request_que.put((host,port,url,is_https,data.inb))
else:
# This means that no data has been received and the client's
# socket object has been closed.
print('closing connection to ', data.addr)
# Undo monitoring of the current sock object
self.sel1.unregister(sock)
sock.close()
if mask & selectors.EVENT_WRITE:
if data.outb:
print(f'Main-Thread {sock}:{data.outb}')
print('echoing', repr(data.outb), ' to ', data.addr)
sent = sock.send(data.outb)
data.outb = data.outb[sent:]
# end-if
# end-def
#end-class
if __name__=='__main__':
server=Server(args.host,args.port,request_que)
server.start()
I've seen and read a lot about this particular issue on the internet.
I am writing a simple chat server and client using socket in python for learning purpose mainly.
I've observed an issue here.
Here is my server code :
__author__ = 'pchakraverti'
import socket
import select
import sys
class NickSocketMap(object):
count = 0
def __init__(self, nick, client_socket):
self.nick = nick
self.client_socket = client_socket
NickSocketMap.count += 1
#staticmethod
def display_count():
print "Total number of clients is %d" % NickSocketMap.count
host = ""
port = 7575
socket_list = []
nick_list = []
cnt = 0
recv_buffer = 1024
def register_nick(nick, client_socket):
obj = NickSocketMap(nick, client_socket)
nick_list.append(obj)
def process_request(request_string, client_socket):
parts = request_string.split("|")
if parts[0] == "set_nick":
register_nick(parts[1], client_socket)
client_socket.send("nick_set")
elif parts[0] == "transmit_msg":
broadcast_message(parts[1], parts[2])
return 1
def broadcast_message(message, client_nick):
for s in nick_list:
if s.nick == client_nick:
try:
s.client_socket.send(message)
except socket.errno, ex:
print ex
break
def run_server():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((host, port))
except socket.errno, ex:
print ex
sys.exit(-1)
sock.listen(10)
# add the parent socket in the list
socket_list.append(sock)
# keep the server alive
while True:
try:
read_ready, write_ready, in_error = select.select(socket_list, [], [], 0)
except select.error, ex:
print ex
continue
for s in read_ready:
# check if s is the parent socket
if s == sock:
# accept new connection and append to list
try:
con, addr = s.accept()
if con not in socket_list:
socket_list.append(con)
except socket.errno, ex:
print ex
else:
try:
# receive packet from connected client
packet = s.recv(recv_buffer)
if not packet:
socket_list.remove(s)
read_ready.remove(s)
for n in nick_list:
if n.client_socket == s:
nick_list.remove(n)
break
break
print packet
except socket.errno, ex:
print ex
continue
process_request(packet, s)
sock.close()
if __name__ == "__main__":
run_server()
and here is my client code:
__author__ = 'pchakraverti'
import socket
nick = ""
host = "192.168.0.167"
port = 7575
sock = ""
def welcome():
print "Welecome to SecuChat!"
print "---------------------"
def init():
nick = raw_input("Enter your chat nickname : ")
print nick
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
except socket.errno, ex:
print ex
sock.send("set_nick|"+nick)
#sock.close()
if __name__ == "__main__":
welcome()
init()
In the client code, when I don't do the sock.close(), the server runs into an exception :
Traceback (most recent call last):
File "server.py", line 102, in <module>
run_server()
File "server.py", line 84, in run_server
packet = s.recv(recv_buffer)
socket.error: [Errno 104] Connection reset by peer
how ever, when I add that line, the problem doesn't occur.
Now I've two questions :
i) I've handled exceptions in the server.py, why is this exception not being handled and why is it crashing the code ? How can I make the server more robust and what am I missing ?
ii) What is the logic behind this crash and exception in relation to the sock.close() line in the client ?
i) Your try-except block doesn't catch any exceptions.
The first argument to except must be the type of the exception you want to catch. socket.errno is not an exception class but a module. You need to catch socket.error:
except socket.error, ex:
print ex
It "crashes" your code because any exception that isn't handled somewhere in the call stack propagates outwards until it hits an except. If there is no handler the program is terminated.
ii) When the client terminates without closing the connection, a RST packet is sent by the TCP/IP stack of your OS. This is roughly the equivalent of hanging up a phone without saying goodbye. Python converts this into an exception with the text "Connection reset by peer". It simply means that since you called read() Python assumed you expect to receive something and when the connection suddenly disconnected, Python informs you of this by raising the exception.