[RESUELTO] ejecutar recv() temporalmente | Python3 sockets

Iniciado por Drakaris, 11 Agosto 2020, 13:16 PM

0 Miembros y 1 Visitante están viendo este tema.

Drakaris

RESUELTO

El resultado fue crear en el cliente un nuevo subproceso donde este en escucha a la respuesta del mensaje OK o TooManyClients, y con cuya respuesta guardarla en un booleano en la clase Globals y con ello hacer el condicional.

Y en el servidor cuando se conecta un cliente almacena en la lista  list_clients, creada en la clase Globals, una sublista con el nombre del cliente "SockServicesX", la conexion, y el booleano (por defecto False).
Más tarde creo la clase Select_user que es para seleccionar la sublista correspondiente al cliente conectado y con ello usar esa información para eliminar el usuario (sublista) con user.remove_client() o check la conexión user.check(conn)


Dejo el código en el proximo post

En conclusión no puede haber dos funciones recv() en una misma conexion socket

Buenas, estoy haciendo una conexion socket con varios clientes... con un máximo de 3 clientes. La idea es
la siguiente:

socket server completo
Código (python) [Seleccionar]

#!/usr/bin/python3
# Server
import socket, threading, os, sys, time

# globals variables
class globals:
PORT, NUMBER_CONNECTIONS = 2048, 3 #constants
number_client = 0 # count clients number

### CONNECTIONS CLIENTS PARALLEL ###

def client(connection, address, idle):

ADDRESS_CLIENT, PORT_CLIENT = address[0], address[1]

print("client "+str(idle)+" ["+str(ADDRESS_CLIENT)+"] connected by "+str(PORT_CLIENT))
while True:
data = connection.recv(1024)

if data.decode() == "exit" or data.decode() == "close":
connection.sendall(b"GoodBye")
print("Client "+str(idle)+" ["+str(ADDRESS_CLIENT)+":"+str(PORT_CLIENT)+"] left")
globals.number_client-=1 # subtract client at count
break
elif data.decode() == "KeyboardInterrupt":
print("[\033[0;31m*\033[0m] Connection interrupted with Client "+str(idle))
globals.number_client-=1 # subtract client at count
break
else:
connection.sendall(data)

#close the connection with client
connection.close()

### MAIN ###
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",globals.PORT))
sock.listen(globals.NUMBER_CONNECTIONS)
print("[\033[0;34m*\033[0m] Listening port "+str(globals.PORT)+"....")
while True:
conn, addr = sock.accept()
# if he is fourth client o more, not connect it
if not globals.number_client+1 > globals.NUMBER_CONNECTIONS:
globals.number_client+=1 # add client at count
idle="SockServices"+str(globals.number_client)
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle))
;
socket_client.start()
else:
conn.sendall(b"TooManyClients")

except KeyboardInterrupt:
# close the server
print("\n[\033[1;34m*\033[0m] Closing server....")
sock.close()
os.system("fuser -k -n tcp %s 2>&1" % globals.PORT)


explicación

variables globales
Código (python) [Seleccionar]

# globals variables
class globals:
PORT, NUMBER_CONNECTIONS = 2048, 3 #constants
number_client = 0 # count clients number


Creo una conexion socket nomal. [globals es una clase con las variables que se van a utilizan en todo el script (también en dentro de funciones)]

Código (python) [Seleccionar]


sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",globals.PORT))
sock.listen(globals.NUMBER_CONNECTIONS)
print("[\033[0;34m*\033[0m] Listening port "+str(globals.PORT)+"....")
while True:
conn, addr = sock.accept()
# if he is fourth client o more, not connect it
if not globals.number_client+1 > globals.NUMBER_CONNECTIONS:
globals.number_client+=1 # add client at count
idle="SockServices"+str(globals.number_client)
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle));
socket_client.start()
else:
conn.sendall(b"TooManyClients")


Cuando corre el bucle si es 1º,2º o 3º cliente la variable globals.number_client con valor por defecto 0 es incrementado, y creo una idle que es el nombre SockServices mas el numero de cliente, después creo un hilo con nombre SockServices donde va a ejecutar la funcion client


if not globals.number_client+1 > globals.NUMBER_CONNECTIONS:
globals.number_client+=1 # add client at count
idle="SockServices"+str(globals.number_client)
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle));
socket_client.start()


Si la condición no se cumple, significa que ya hay tres clientes y me envias al cliente con conexion denegada la palabra "TooManyClients"

Código (python) [Seleccionar]

else:
conn.sendall(b"TooManyClients")


socket client completo

Código (python) [Seleccionar]

#!/usr/bin/python3
#client
import socket, time, os, sys

# CONSTANTS
ADDRESS, PORT = "127.0.0.1", 2048

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ADDRESS, PORT))
sock.settimeout(3)

while True:
try:
try:
#receive server's data
check = sock.recv(1024)
except socket.timeout:
pass

if check.decode() == "TooManyClients":
print("[\033[0;31m*\033[0m] Too many clients connected")
sock.close()
sys.exit()
else:
print("[\033[0;32m*\033[0m] Connection established")
pass

sock.setblocking(s)
while True:
#prompt terminal
prompt = input("> ")

#receive server's data
data = sock.recv(1024)

print(data.decode())

#Send prompt's data to server
sock.sendall(prompt.encode())

if data.decode() == "GoodBye":
print("[\033[0;34m*\033[0m] Closing connection....")
break
except KeyboardInterrupt:
sock.sendall(b"KeyboardInterrupt")
print("\n[\033[0;31m*\033[0m] Connection interrupted, closing connection....")
break
sock.close()


explicación

Creo una conexion socket normal y me conecto al servidor

Código (python) [Seleccionar]

# CONSTANTS
ADDRESS, PORT = "127.0.0.1", 2048

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ADDRESS, PORT))


Una vez hecha la conexion ejecuto el primer bucle while True, que lo ejecuto para saber si el cliente se puede conectar o no.
Primero recibo los datos del servidor

Código (python) [Seleccionar]

while True:
try:
#receive server's data
data = sock.recv(1024)


Sí lo que recibo es TooManyClients, le digo al cliente que no se puede conectar porque el foro de clientes está completo y cierro la conexion

Código (python) [Seleccionar]

if data.decode() == "TooManyClients":
print("[\033[0;31m*\033[0m] Too many clients connected")
sock.close()
sys.exit()


Si no recibo nada imprime que esto conectado al servidor y ejecuta el siguiente bucle.

Código (python) [Seleccionar]

else:
print("[\033[0;32m*\033[0m] Connection established")
pass
while True:
#prompt terminal
prompt = input("> ")

print(data.decode())

#Send prompt's data to server
sock.sendall(prompt.encode())

if data.decode() == "GoodBye":
print("[\033[0;34m*\033[0m] Closing connection....")
break


Que el siguiente bucle ya podré enviar datos al servidor

problema

Como podeis ver en la imagen cuando me conecto, no me imprime el mensaje Connection establlished, sino que se queda como en escucha, en el cuarto intento de conexión (cuadro izquierdo abajo), me imprime el mensaje Too many clients connected

Creo que el problema esta en el lado cliente, en el primer while True, que esta recibiendo los datos

Código (python) [Seleccionar]

sock.connect((ADDRESS, PORT))
while True:
try:
#receive server's data
data = sock.recv(1024)


El problema es que el recv() se queda en escucha y como no recibe nada... ya que el condicional if que valida el usuario en socket server no envia nada al cliente.

Código (python) [Seleccionar]

if not globals.number_client+1 > globals.NUMBER_CONNECTIONS:
globals.number_client+=1 # add client at count
idle="SockServices"+str(globals.number_client)
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle));
socket_client.start()
else:
conn.sendall(b"TooManyClients")



Sí en la condicional if le envio un OK, y con esto, se me inicia pero si envio algo del cliente al servidor siempre me recibe el mensaje OK, y no GoodBye

Código (python) [Seleccionar]

if not globals.number_client+1 > globals.NUMBER_CONNECTIONS:
                       conn.sendall(b"OK")
globals.number_client+=1 # add client at count
idle="SockServices"+str(globals.number_client)
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle));
socket_client.start()
else:
conn.sendall(b"TooManyClients")



Como la idea de enviar el mensaje OK no funciona... me preguntaria si se podría en el cliente dejar de escuchar los datos a recibir recv(), hacer la condicional y después volver a escuchar los datos.. Se puede hacer esto con sock.setblocking()?
Código (python) [Seleccionar]

while True:
try:
#receive server's data
data = sock.recv(1024)
if data.decode() == "TooManyClients":
print("[\033[0;31m*\033[0m] Too many clients connected")
sock.close()
sys.exit()
else:
print("[\033[0;32m*\033[0m] Connection established")
pass


Leí un post en stackoverflow, donde preguntaba como podía recibir datos con recv() un tiempo con select
https://stackoverflow.com/questions/2719017/how-to-set-timeout-on-pythons-socket-recv-method#answer-2721734

Yo lo que hice es lo siguiente:

importe el modulo select
Código (python) [Seleccionar]
import select

dentro del bucle cree una variable ready que le permite escuchar el rec() solo 2 segundos y cuando acabe estos segundos. Mientras pasa estos dos segundos, recibo los datos en la variable data y si data contiene TooManyClients la varibale booleana es False (por defecto es True).

Si la variable es True ejecutaré el pass y pasará al siguiente while y si es False me imprimira que hay demasiados clientes.

Código (python) [Seleccionar]

sock.setblocking(0)
check = True
while True:
try:
ready = select.select([sock], [],  [], 2)
if ready[0]:
#receive server's data
data = sock.recv(1024)
if data.decode() == "TooManyClients":
check=False
if check==False:
print("[\033[0;31m*\033[0m] Too many clients connected")
sock.close()
sys.exit()
else:
print("[\033[0;32m*\033[0m] Connection established")
pass


Pero tengo dos problemas con esta solucion

  • Este script se ejecutará en sistemas Windows y Linux y en Windows el modulo select no funcionara
  • Cuando estoy ya conectado al servidor y envio un dato, este no me leé la variable data

Se puede en:

Código (python) [Seleccionar]

else:
print("[\033[0;32m*\033[0m] Connection established")
pass

o en:
Código (python) [Seleccionar]

while True:
#prompt terminal
prompt = input("> ")

print(data.decode())

#Send prompt's data to server
sock.sendall(prompt.encode())



Volver a activar el recv()? Y si se puede como?



actualizado

Buenas como mi idea es que recv() se ejecute temporalmente en el primer while True del cliente inserte lo siguiente:

Código (python) [Seleccionar]

sock.connect(...)
sock.settimeout(3)

while True:
try:
try:
#receive server's data
check = sock.recv(1024)
except socket.timeout:
pass


Durante 3 segundos me ejecuta el sock.recv() y cuando pasa el tiempo me salta la excepcion por la cual pasa al siguiente bucle, el problema esta en que lo que obtuve de recv() lo quisiera almacenar en una variable, teoricamente en check, pero cuando hago las condicionales check.decode() no me detecta cuya variable

Citar
Services
Traceback (most recent call last):
 File "./SockServices", line 16, in <module>
   check = sock.recv(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:                                    

Traceback (most recent call last):
 File "./SockServices", line 18, in <module>
   print(check.decode())
Lo increible, no es lo que ves, sino como es

Drakaris

RESULTADO

servidor

Código (python) [Seleccionar]

#!/usr/bin/python3
# Server
import socket, threading, os, sys, time

# globals variables
class Globals:
PORT, NUMBER_CONNECTIONS = 2048, 3 #constants
number_client = 0 # count clients number
list_clients=[]

# select user's sublist and your index, for later use it
class Select_user:
def __init__(self, idle, port):
for client in Globals.list_clients:
index = Globals.list_clients.index(client)
name_user = Globals.list_clients[index][0]
port_user = Globals.list_clients[index][1][1]
if name_user == idle and port_user == port:
self.index_user = index
self.user = Globals.list_clients[self.index_user]

def remove_client(self):
del Globals.list_clients[self.index_user]

# If the third element of list clients is False, it means that the user is not checked
def check(self, conn):
if Globals.list_clients[self.index_user][2] == False:
conn.send(b"OK")
Globals.list_clients[self.index_user][2] = True

### CONNECTIONS CLIENTS PARALLEL ###

def client(connection, address, idle):
ADDRESS_CLIENT, PORT_CLIENT = address[0], address[1]

user = Select_user(idle, PORT_CLIENT)
user.check(connection)

print("client "+str(idle)+" ["+str(ADDRESS_CLIENT)+"] connected by "+str(PORT_CLIENT))
while True:
data = connection.recv(1024)

if data.decode() == "exit" or data.decode() == "close":
connection.sendall(b"GoodBye")
print("Client "+str(idle)+" ["+str(ADDRESS_CLIENT)+":"+str(PORT_CLIENT)+"] left")
Globals.number_client-=1 # subtract client at count

# delete user of list clients
user = Select_user(idle, PORT_CLIENT)
user.remove_client()
break
elif data.decode() == "KeyboardInterrupt":
print("[\033[0;31m*\033[0m] Connection interrupted with Client "+str(idle)+" ["+str(ADDRESS_CLIENT)+":"+str(PORT_CLIENT)+"]")
Globals.number_client-=1 # subtract client at count

# delete user of list clients
user = Select_user(idle, PORT_CLIENT)
user.remove_client()
break
else:
connection.sendall(data)

#close the connection with client
connection.close()

### MAIN ###
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",Globals.PORT))
sock.listen(Globals.NUMBER_CONNECTIONS)
print("[\033[0;34m*\033[0m] Listening port "+str(Globals.PORT)+"....")
while True:
conn, addr = sock.accept()
# if he is fourth client or higher, not connect it
if not Globals.number_client+1 > Globals.NUMBER_CONNECTIONS:
Globals.number_client+=1 # add client at count
idle="SockServices"+str(Globals.number_client)
Globals.list_clients.append([idle,addr,False]) # add client to list clients
socket_client = threading.Thread(target=client,name=idle,args=(conn, addr, idle));
socket_client.start()
else:
conn.sendall(b"TooManyClients")

except KeyboardInterrupt:
# close the server
print("\n[\033[1;34m*\033[0m] Closing server....")
sock.close()
os.system("fuser -k -n tcp %s 2>&1" % Globals.PORT)


cliente

Código (python) [Seleccionar]

#!/usr/bin/python3
#client
import socket, time, os, sys, threading

# CONSTANTS
class Globals:
ADDRESS, PORT, CHECK = "127.0.0.1", 2048, None

def checking(sock):
while True:
check = sock.recv(1024)
if check.decode() == "TooManyClients":
Globals.CHECK = False
elif check.decode() == "OK":
Globals.CHECK = True
break

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((Globals.ADDRESS, Globals.PORT))

while True:
try:
# Before, we check if the server allow us connect
check = threading.Thread(target=checking, name="check_connection", args=(sock, ))
check.start()
sys.stdout.write("[\033[0;34m*\033[0m] Checking....")
"""After of run the thread, the program wait 3 seconds for receive the server's response
and continue"""
time.sleep(3)

if Globals.CHECK == False:
print("[\033[0;31m*\033[0m] Too many clients connected")
sock.close()
sys.exit()
else:
print("[\033[0;32m*\033[0m] Connection established")
pass
while True:

#prompt terminal
prompt = input("> ")

#Send prompt's data to server
if prompt != "":
sock.sendall(prompt.encode())
else:
continue

#receive server's data
data = sock.recv(1024)

if data.decode() == "GoodBye":
print("[\033[0;34m*\033[0m] Closing connection....")
break
else:
print(data.decode())
break
except KeyboardInterrupt:
sock.sendall(b"KeyboardInterrupt")
print("\n[\033[0;31m*\033[0m] Connection interrupted, closing connection....")
break
sock.close()
Lo increible, no es lo que ves, sino como es