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 postEn conclusión no puede haber dos funciones recv() en una misma conexion socketBuenas, estoy haciendo una conexion socket con varios clientes... con un máximo de 3 clientes. La idea es
la siguiente:
socket server completo
#!/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ónvariables globales# 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)]
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"
else:
conn.sendall(b"TooManyClients")
socket client completo
#!/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ónCreo una conexion socket normal y me conecto al servidor
# 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
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
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.
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 connectedCreo que el problema esta en el lado cliente, en el primer while True, que esta recibiendo los datos
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.
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
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()?
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-2721734Yo lo que hice es lo siguiente:
importe el modulo select
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.
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:
else:
print("[\033[0;32m*\033[0m] Connection established")
pass
o en:
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:
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
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())