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
#!/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
# 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
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
Código:
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
else: conn.sendall(b"TooManyClients")
socket client completo
Código
#!/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
# 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
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
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
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
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
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
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
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
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
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
o en:
else: print("[\033[0;32m*\033[0m] Connection established") pass
Código
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
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())
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())