I have this two threads python program that should stall start_events thread when a receive event happens and there's no message in the call_queue, but when I run the program it just ends itself before another one sends a message to it.
import Queue
import threading
import argparse
import socket, struct
call_queue = Queue.Queue()
def call(host, port, localCounter):
s = socket.socket()
print "Call: " + host + ", " + str(port) + ", " + str(localCounter)
s.connect((host, port))
print s.recv(1024)
s.send(str(localCounter))
def start_events(events):
log = [];
localCounter = 0;
received = False;
for e in events:
localCounter += 1;
event_parts = e.split()
if event_parts[0]=="call":
call(event_parts[1], int(event_parts[2]), localCounter)
print "call"
elif event_parts[0]=="receive":
while call_queue.empty():
#do nothing
pass
remoteCounter = int(call_queue.get())
print "recahed here"
if remoteCounter>=0:
remoteCounter += 1
localCounter = max(localCounter, remoteCounter)
received = True
print "received"
#print "not recived"
log.append([e, localCounter])
print log
def start_listening(port):
s = socket.socket()
host = socket.gethostname()
print "REeceive: " + host + ", " + str(port)
s.bind((host,port))
s.listen(5)
while True:
c, addr = s.accept()
call_queue.put(c.recv(1026))
c.close()
print "lol"
#q.put(urllib2.urlopen(url).read())
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('file')
parser.add_argument('port', type=int)
res = parser.parse_args()
inputfile = res.file
port = res.port
with open(inputfile) as f:
inputRaw = f.readlines()
# you may also want to remove whitespace characters like `\n` at the end of each line
events = [x.strip() for x in inputRaw]
#start events thread
events_thread = threading.Thread(target=start_events, args = (events,))
events_thread.daemon = True
events_thread.start()
#start listening thread
listening_thread = threading.Thread(target=start_listening, args = (port,))
listening_thread.daemon = True
listening_thread.start()
print port
Your code is finishing instantly because you start the threads and do not wait for them to finish. To do so, you must call join() for each thread you started, in your case this means adding:
events_thread.join()
listening_thread.join()
See this answer for details.
Related
I'm setting up a little server with commands and other kind of stuff, but ,I don't get the thread functionement, when I connect my server it seems like everything is okay, I can connect a first client "without" problems, but when I want to connect another client it never get conected , the code runs but I can send anything I want it never shows up on the other client or the server.
I've already read the Threading documentation but even with the exemples, I don't get it, can someone give me some clues about how to proceed to handle more than just one client?
the server code :
#!/usr/bin/python3+x
import socket
import sys
from time import sleep
import threading
import random
HOST = "localhost"
PORT = 33700
MSG_SIZE = 32768
serveur_on = True
CLIENT_NICK_CHAN = {} #clients" nicks dict like {nickname : channel} -> needed to easily know who is where
CLIENT_NICK_SOCKET = {} #clients" dict like {nickname : socket} -> needed to send private message to the nickname's socket easily
CLIENT_NICK_THREAD = {} #clients" dict with like {nick : thread}
Rand_disconnection_msg = [" has drown in the abyss.", " is disconnected.", " is now in a better place.", " is now a part of our past", " passed away, in really tragic circumstances..."]
CHANNELS = ["main lobby", "test"]
CMD_LIST = [b"HELP",b"NICK",b"JOIN",b"CHANNELS",b"LEAVE"]
COMMANDS = ["/NICK <nickname>: Use only when you\'re connecting, allow you to choose a unique nickname",
"/JOIN <channel_name>: Allow you to join or create a channel, you can\'t use this command if your are already in another channel than the" + CHANNELS[0],
"/CHANNELS : Allow you to see every channels on the server with every connected people",
"/LEAVE : You leave the channel your within and get bringed back to the" + CHANNELS[0],
"/HELP : Gives you the whole command list",
"/BYE : Disconnect ou from the server, you have to in the " + CHANNELS[0] + " to use this command"
]
class Colors:
Blue, Cyan, Green, Red, Magenta, Yellow, White =b"\033[94m", b"\033[96m", b"\033[92m", b"\033[91m", b"\033[95m", b"\033[93m", b"\033[0m"
Normal, Bold, Italics, Thin = b"\033[0m", b"\033[1m", b"\x1B[3m", b"\033[2m"
class thread_client(threading.Thread):
def __init__(self,conn):
self.nom = ""
if(self.nom == ""):
nickname_input(connexion, self)
print("nom : " + self.nom.decode("utf8"))
self.channel = CHANNELS[0]
self.admin = False
self.adress = ""
threading.Thread.__init__(self)
self.connexion = conn
print("init done")
def run(self):
while True:
msgClient = self.connexion.recv(MSG_SIZE)
if not msgClient or msgClient == b"BYE":
break
print(type(self.nom))
print(type(msgClient))
str_name = self.nom.decode("utf8")
msg = str_name + " > " + msgClient.decode("utf8")
print("string type name is : " + str_name + "\n")
str_msg = msgClient.decode("utf8")
print("{} > {}".format(str_name, str_msg))
for clients in CLIENT_NICK_SOCKET:
if clients != self.nom:
CLIENT_NICK_SOCKET[clients].send(bytes(str_msg,"utf8"))
self.connexion.send(b"You are now disconnected.\n")
self.connexion.close()
del CLIENT_NICK_SOCKET[self.nom.decode("utf8")]
del CLIENT_NICK_CHAN[self.nom.decode("utf8")]
rand_leave = random.randint(0, len(Rand_disconnection_msg)-1)
leaving_msg = Rand_disconnection_msg[rand_leave]
print(str_name + leaving_msg + "\n")
def nickname_input(client_socket, thread):
print("now in input nickname")
msg_nom = client_socket.recv(MSG_SIZE)
print("msg_nom = " + msg_nom.decode("utf8"))
msg_nom_arr = msg_nom.split()
if not msg_nom_arr[0]:
client_socket.send(b"Please send a non void message")
nickname_input(client_socket, thread)
print("msg_nom_arr[0] = " + str(msg_nom_arr[0]))
if(msg_nom_arr[0] == b"NICK"):
if(len(msg_nom_arr)== 1):
client_socket.send(b"Please do not just enter '/NICK' -> you have to type '/NICK <your_nickname>', please proceed again :\n")
nickname_input(client_socket, thread)
else:
thread.nom = msg_nom_arr[1]
else:
client_socket.send(b"It seems like you forgot to use '/NICK' before entering your nickname, please proceed again:\n")
nickname_input(client_socket, thread)
return
def print_channels(client_socket, thread):
client_socket.send(b"Here\'s the current channel list :\n\n")
for chan in CHANNELS:
sleep(0.70)
client_socket.send( bytes(chan,"utf8") + b":\n current members :\n")
for chan_user in CLIENT_NICK_CHAN:
if(CLIENT_NICK_CHAN[chan_user] == chan):
sleep(0.35)
if(chan_user == thread.nom):
if(thread.admin):
client_socket.send(b" " +Colors.Bold + Colors.Yellow + b"#"+ thread.nom + b"#" + Colors.Normal + b"\n")
else:
client_socket.send(b" " +Colors.Bold + Colors.Yellow + thread.nom + Colors.Normal + b"\n")
else:
client_socket.send(b" " +bytes(chan_user,"utf8") + b"#\n")
client_socket.send(b"\n")
client_socket.send(b"\n")
return
def join_channel(client_socket, thread, data, data_array):
if(not data_arr[1]):
connexion.send(b"Please select a channel you want to join using '/JOIN <channel_name>'\nNote that if the channel you asked for doesn\'t exists a new channel <channel_name> will be created and you will be the administrator of this channel")
return
else:
asked_channel = data_arr[1]
if( not (asked_channel in CHANNELS)):
thread.channel = asked_channel
thread.admin = True
connexion.send(b"Welcome in " + asked_channel + b" channel, since you\'re the on who created this channel you are granted as administrator for this channel")
connexion.send(b"Note that being administrator allow you tu use some new commands as '/GRANT', '/REVOKE' or '/REN', for more information please use '/HELP'")
else:
thread.channel = asked_channel
connexion.send(b"Welcome in " + asked_channel + b" channel !")
return
SERVER = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
SERVER.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
try:
SERVER.bind((HOST,PORT))
except socket.error:
print("Server connexion failed")
sys.exit()
print("Server is now connected\nWaiting for connexions...\n")
SERVER.listen(5)
connexion, adresse = SERVER.accept()
thread = thread_client(connexion)
thread.start()
print("thread type = " +str(type(thread)) +"\n")
print("thread = ")
print(thread)
connexion.send(bytes("Welcome ","utf8") + Colors.Yellow + Colors.Bold + thread.nom + Colors.Normal)
nick = thread.nom #type -> bytes
str_nick = nick.decode("utf8")
CLIENT_NICK_CHAN[str_nick] = thread.channel
CLIENT_NICK_SOCKET[str_nick] = connexion
CLIENT_NICK_THREAD[str_nick] = thread
print("client list : ")
print(CLIENT_NICK_CHAN)
print("\n")
print("CLIENT_NICK_SOCKET = ")
print(CLIENT_NICK_SOCKET)
print("\n")
while serveur_on:
conn_msg = str_nick + " joined the chat\n"
print(conn_msg)
connexion.send(b"hello world 3\n\n")
connexion.send(b"*" * 80 + b"\n")
connexion.send(Colors.Red + Colors.Bold + b"\nWELCOME IN THE MAIN LOBBY \n" + Colors.Normal+b"\nTo enter a channel use '/JOIN <channel_name>'\nthe <channel_name> have to be composed by one world or use underscores to join words\nIf the channel does not exists a new one will be created\n\nNote that you have to be in another channel than the main lobby to chat\n")
print_channels(connexion, thread)
connexion.send(b"*" * 80 + b"\n\n")
while True:
print("thread list = ")
print(CLIENT_NICK_THREAD)
data = connexion.recv(MSG_SIZE) #receiving data from client
data_arr= data.split() #convert data into an array to check if the first word in the message is "MSG" or not
print(str_nick +" is now in -> " + thread.channel + "\n")
if(data_arr[0] in CMD_LIST):
if(data.startswith(b"HELP")): #HELP CMD
for command in COMMANDS:
connexion.send(bytes(command,"utf") + b"\n")
if(data.startswith(b"CHANNELS")): #Channels + current members CMD
connexion.send(b"\n")
print_channel(connexion, thread)
connexion.send(b"\n")
if(data.startswith(b"JOIN")):
join_channel(connexion, thread, data, data_arr)
connexion.send(b"\n")
else:
if ((thread.channel != CHANNELS[0]) and (data.startswith("MSG"))):
for chan_user in thread.channel:
chan_user.send(nick + b" > " + bytes(data,"utf8"))
print("data = " + data)
elif (thread.channel == CHANNELS[0]):
connexion.send(b"You have to be in another channel than the " + bytes(CHANNELS[0], "utf8") + b" to start chating !\nPlease use '/JOIN <channel_name>' or '/HELP' to learn how to join another channel.\n\n")
and the client code:
#!/usr/bin/python3+x
host = ''
port = 33700
MSG_SIZE = 32768
emission_stop = False
import socket
import sys
import threading
import time
def Tsend():
while True:
msg_envoi = input("> ")
if msg_envoi.startswith("/"):
msg_envoi = msg_envoi.replace("/","",1)
else:
msg_envoi = msg_envoi
CLIENT.send(bytes(msg_envoi,"utf8"))
if emission_stop:
CLIENT.close()
def Trecv():
while True:
msg_recu = CLIENT.recv(MSG_SIZE).decode("utf8")
print("\n" + msg_recu)
if not msg_recu:
break
emission_stop = True
print("connexion lost\n")
CLIENT.close()
CLIENT = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
try:
CLIENT.connect((host,port))
except socket.error:
print("connexion failed\n")
sys.exit()
print("Now connected to the server on port: {}\n".format(port))
print("Please now enter your nickname using '/NICK'\n")
thread_emission = threading.Thread(target = Tsend)
thread_reception = threading.Thread(target = Trecv)
thread_emission.start()
thread_reception.start()
What I want is just to have multiple clients that are allowed to talk to each other but I can't even get two clients.
The biggest problem I can see is that you are only calling SERVER.accept() once. This means you will only ever accept 1 client connection. When using blocking sockets as you are, a typical approach is to keep doing SERVER.accept() inside a loop so that you can keep accepting all client sockets. After you accept() a new socket, you create new thread(s) dedicated to sending/receiving for that socket, so that you don't block the accepting thread. And then you continue accepting more connections. Something like this:
#SERVER:
while serveur_on:
connexion, adresse = SERVER.accept()
# Possibly do some limited IO with client socket here, but be careful not
# to block this thread too long because that will prevent more clients from
# connecting.
thread = thread_client(connexion)
thread.start()
# No more client IO on this thread, it's the client thread's job now.
You seem to have code that communicates with the client (receiving messages and sending responses) in 2 different places: on the main thread after you SERVER.accept(), and up in thread_client.run(). It doesn't make sense that way, it should all be in thread_client.run().
I'm coding a small socket Chat Server for personal use, and have come across and issue.
My client is a simple program with two threads, one waiting on a user input, the other on the server; this code works perfectly:
import socket
import threading
from threading import Thread
username = input("Username? >")
host = input("host ip?")
port = 8000
Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Socket.connect((host,port))
Socket.send(username.encode())
print(Socket.recv(1024).decode())
def SendMessage():
while True:
Socket.send(input("").encode())
def RecvMessage():
while True:
print(Socket.recv(1024).decode())
msgthread = Thread(target = SendMessage, args = ())
recvthread = Thread(target = RecvMessage, args = ())
msgthread.start()
recvthread.start()
(Forgive the sloppy code, it was thrown together in ~20mins on a Monday evening)
As you can see, I am calling two threads, both of which have halting functions in them, and it works seamlessly.
The server, however, is where I am having problems:
import socket
import threading
from threading import Thread
connections = []
host = ""
port = 8000
threads = []
def ListenForCommands():
while True:
print(input())
def SearchForConnections():
global connections, threads
while True:
conn, addr = Socket.accept()
username = conn.recv(10).decode()
conn.send(("You have successfully connected to the server!").encode())
print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
for i in range(len(connections)):
if connections[i][0] != conn:
connections[i][0].send((username + " Joined").encode())
connections += [[conn,addr,username]]
threads += [Thread(target = Listen, args = (conn, ))]
threads[-1].start()
def Listen(conn):
global connections, threads
while True:
for i in range(len(connections)):
if connections[i][0] == conn:
username = connections[i][2]
try:
data = conn.recv(1024).decode()
print(username + ": " + data)
for i in range(len(connections)):
if connections[i][0] != conn:
connections[i][0].send((username + ": " + data).encode())
except:
print(username + " Disconnected")
for i in range(len(connections)):
if connections[i][0] == conn:
connections.remove(connections[i])
break
for i in range(len(connections)):
connections[i][0].send((username + " Disconnected").encode())
return;
Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Server created")
Socket.bind((host,port))
Socket.listen(3)
ListenThread = Thread(target = ListenForCommands, args = ())
ListenThread.start()
SearchForConnections()
The source of the problem is in these functions:
def ListenForCommands():
while True:
print(input())
def SearchForConnections():
global connections, threads
while True:
conn, addr = Socket.accept()
username = conn.recv(10).decode()
conn.send(("You have successfully connected to the server!").encode())
print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
for i in range(len(connections)):
if connections[i][0] != conn:
connections[i][0].send((username + " Joined").encode())
connections += [[conn,addr,username]]
threads += [Thread(target = Listen, args = (conn, ))]
threads[-1].start()
The program seems to be halting when arriving at this line
print(username + " (" + str(addr[0]) + ":" + str(addr[1]) + ") Joined")
and works fine without it; however, on the Client Program, this does not seem to be the case.
the ListenForCommands function (as of now just printing out the user input) is being declared as a thread:
ListenThread = Thread(target = ListenForCommands, args = ())
ListenThread.start()
and the SearchForConnections function is being called normally. However, the entire program seems to be being halted until an input is taken from the user, unlike the client side which seems to be working perfectly.
I think I am missing something quite obvious, but have been at a loss for a few hours now, and would love it if someone could help me see the error in my ways!
The Client and Server can successfully connect however only one command can be issued. Been at this for a while and wanted some outside help, any feedback or suggested improvements would be great thanks in advance.
Been looking at other posts which suggest I may have prematurely closed the connection but I don't believe this to be true due to the fact the program doesn't throw any disconnection errors though I may be wrong.
client.py
import socket
import sys
import os
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
##server = input("Enter server IP: ")
##print(server)
##
##port = int(input("Enter port: "))
##print(port)
def send_msg(msg):
sock.sendall(msg.encode())
def get_msg():
msg = sock.recv(2048).decode()
return msg
server = "127.0.0.1"
port = 100
sock.connect((server, port))
print("Connecting to " + server + " on port " + str(port) + "\n")
while True:
#Send data
msg = input(os.getcwd() + "> ")
print("Sending '" + msg + "'")
send_msg(msg)
#Response
#amnt_exp = len(msg)
#data = sock.recv(2048)
data = get_msg()
if data == "exit":
print("\nClosing connection")
sock.close()
else:
print("Received: \n" + data)
server.py
import socket
import sys
import os
import subprocess
#Create a TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
##server = input("Enter server IP: ")
##print(server)
##
##port = int(input("Enter port: "))
##print(port)
def send_msg(msg):
conn.sendall(msg.encode())
def get_msg():
msg = conn.recv(2048).decode()
return msg
server = "127.0.0.1"
port = 100
#Config
sock.bind((server, port))
print("Bound to " + server + " on port " + str(port) + "\n")
sock.listen(1)
print("Waiting for a connection...")
while True:
conn, caddr = sock.accept()
print("Connected!\n")
print("Waiting for a command...")
#data = conn.recv(2048).decode()
data = get_msg()
#Exit
if data == "exit":
print("\nConnection closed")
conn.close()
print("Received '" + data + "'")
#Command Exec
call = subprocess.Popen(data, stdout = subprocess.PIPE, shell=True)
#Output
output, err = call.communicate()
call_status = call.wait()
#print("Output: ", output)
#print("Exit status: ", call_status)
#Reply
msg = "Command successful\n" + "Output: " + str(output) + "\n" + "Exit status:" + str(call_status)
print("Sending reply...")
print("\nWaiting for a command...")
send_msg(msg)
The problem is that your server loop only accepts a single command, and then it goes back to accept a whole new connection, and never looks at the old connection again.
Your output is pretty misleading, because it does print out Waiting for a command.... But that's only happening because you have an extra print("\nWaiting for a command...") before send_msg, and you don't have any output before sock.accept. You can see what's actually happening if you make your prints accurate. For example:
sock.listen(1)
while True:
print('Waiting for a connection...') # inside the loop, not before it
conn, caddr = sock.accept()
# ... etc. ...
print("Sending reply...")
# Don't print Waiting for a command here, because you aren't
send_msg(msg)
# And print something after the send succeeds
print("Sent")
print()
So, now you know what's wrong, how do you fix it?
Simple. We just need a nested loop. Once you accept a client connection, keep using that connection until they exit:
sock.listen(1)
while True:
print('Waiting for a connection...') # inside the loop, not before it
conn, caddr = sock.accept()
print("Connected!\n")
while True:
print("Waiting for a command...")
data = get_msg()
#Exit
if data == "exit":
print("\nConnection closed")
conn.close()
break # go back to the outer accept loop to get the next connection
print("Received '" + data + "'")
# ... etc. ...
print()
I am writing a Python based application for which I am using socket programming.
I am following below approach.
Created 1 TCP/IP server, 1 controller TCP/IP client thread and 3 TCP/IP Clients threads.
I want the application to work like this. Whenever controller sends a message it gets broadcast to all 3 TCP/IP clients. Upon received message from controller the client threads perform some task and send data to the server.
Now server has to send this data to controller thread.
The communication part for of the clients and controller is working fine.
Only problem which I am facing is server is putting all the data received from clients to controller socket together.
I want server should put 1 Client thread's data on controller socket, Wait for that data to be picked up. Then place next thread's data.
So far I am using SOCK_STREAM for sockets.
Library:-
#!/usr/bin/python
import select, socket, sys, Queue, errno
usable_port_start = 40000
Internal_ip = "127.0.0.1"
class getTCPports(object):
def __init__(self,starting_port=usable_port_start,address=Internal_ip):
super(getTCPports, self).__init__()
self.IP_address = address
i = 1
delta = 0
while i <= 1:
delta += 2
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
try_port=starting_port + delta
s.bind((self.IP_address,try_port))
self.free_port=try_port
i+=1
except socket.error as e:
if e.errno == errno.EADDRINUSE:
print("Port" , try_port , "is already in use")
else:
# something else raised the socket.error exception
print(e)
s.close()
class IPCLib(getTCPports):
server_port = 0
controller_port = 0
client_map = {}
def __init__(self):
super(IPCLib,self).__init__()
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((self.IP_address, self.free_port))
self.inputs = [self.socket]
self.is_alive = True
self.broadcast_list = []
#classmethod
def modify_server_port(cls,port):
cls.server_port = port
#classmethod
def modify_client_port(cls,identity,port):
if 0 <= identity.find("CONTROLLER"):
cls.controller_port = port
elif 0 <= identity.find("CLIENT"):
cls.client_map[identity] = port
def start_TCP_server(self):
self.socket.setblocking(0)
self.socket.listen(10)
self.modify_server_port(self.free_port)
while self.is_alive:
inputready,outputready,exceptready = select.select(self.inputs,[],[])
for s in inputready: #check each socket that select() said has available data
if s == self.socket: #if select returns our server socket, there is a new
#remote socket trying to connect
client, address = s.accept()
self.inputs.append(client) #add it to the socket list so we can check it now
self.broadcast_list.append(client)
#print 'new client added%s'%str(address)
else:
# select has indicated that these sockets have data available to recv
data = s.recv(4096)
if data:
#print '%s Received From Client(on server)-> %s'%(data,s.getpeername()[1])
#Uncomment below to echo the recv'd data back
#to the sender... loopback!
if s.getpeername()[1]==self.controller_port:
self.broadcast(data)
else: #if sender is monitoring clients, send data to only controller
self.send_to_controller(data)
else:#if recv() returned NULL, that usually means the sender wants
#to close the socket.
s.close()
self.inputs.remove(s)
#if running is ever set to zero, we will call this
server.close()
def start_TCP_client(self,identity):
self.modify_client_port(identity,self.free_port)
self.socket.connect((self.IP_address,self.server_port))
def stop_TCP_client(self):
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
def broadcast(self,message):
for client in self.broadcast_list:
if client.getpeername()[1]!=self.controller_port:
try:
client.send(message)
except:
client.close()
# if the link is broken, we remove the client
remove(clients)
def send_to_controller(self,message):
for client in self.broadcast_list:
if client.getpeername()[1]==self.controller_port:
try:
client.send(message)
except:
client.close()
# if the link is broken, we remove the client
remove(clients)
def send_data(self,data):
self.socket.send(data)
def receive_data(self):
message = self.socket.recv(4096)
return message
Driver Program:-
#!/usr/bin/python
from IPCLib import *
import threading
import os
import time
def run_server():
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_server()
def run_controller(identity):
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_client(identity)
print("server port " , i1.server_port)
print("controller port", i1.controller_port)
print("bsc info", i1.client_map)
time.sleep(1)
while i1.is_alive:
i1.send_data("hello")
print"Next Clock"
sender_map={}
sender_list = []
sender_list = i1.client_map.values()
for sender in sender_list:
sender_map[sender] = False
i=1
#print any(sender_map.values())
while any(value == False for value in sender_map.values()):
print("Loop Iteration %s"%i)
data = i1.receive_data()
temp = data.split(",")
port = temp.pop(0)
sender_map[int(port)] = True
data = ",".join(temp)
print("Data %s received from port %s"%(data,port))
print sender_map
i+=1
print sender_list
time.sleep(1)
i1.stop_TCP_client()
def run_monitors(identity):
i1=IPCLib()
print("Task assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task: {}".format(os.getpid()))
i1.start_TCP_client(identity)
print("server port " , i1.server_port)
print("controller port", i1.controller_port)
print("bsc info", i1.client_map)
while i1.is_alive:
if i1.receive_data():
output = "%d"%i1.free_port
output = output + "," + "Hello"
i1.send_data(output)
i1.stop_TCP_client()
# creating thread
t1 = threading.Thread(target=run_server, name='server')
t3 = threading.Thread(target=run_monitors, name='Client1',args=("CLIENT-1",))
t4 = threading.Thread(target=run_monitors, name='Client2',args=("CLIENT-2",))
t5 = threading.Thread(target=run_monitors, name='Client3',args=("CLIENT-3",))
t6 = threading.Thread(target=run_monitors, name='Clinet4',args=("CLIENT-4",))
#make threads deamons
t1.daemon = True
t3.daemon = True
t4.daemon = True
t5.daemon = True
t6.daemon = True
# starting threads
try:
t1.start()
time.sleep(0.1)
t3.start()
time.sleep(0.1)
t4.start()
time.sleep(0.1)
t5.start()
time.sleep(0.1)
t6.start()
time.sleep(0.1)
run_controller("CONTROLLER")
except KeyboardInterrupt:
t1.is_alive = False
t3.is_alive = False
t4.is_alive = False
t5.is_alive = False
t6.is_alive = False
How can I force server to wait till the time there is already some data on the socket?
I am trying to figure out how to get my client to send and receive data 'simultaneously' and am using threads. My problem is that, depending on the way I set it up, the way here it waits for data from the server in the recieveFromServer function which is in its own thread and cannot stop it when nothing will be sent. The other way it just waits for user input, and will send to the server and then I'd call the function recieveFromServer after the client sends a message to the server which doesn't allow for fluent communication, but cannot get it to alternate automatically. How do I release the thread when the client has nothing to be sent, or there is no more to be received from the server.
It would get to long if I tried to explain everything I have tried. :)
Thanks.
The client:
from socket import *
from threading import *
import thread
import time
from struct import pack,unpack
from networklingo import *
#from exception import *
HOST = '192.168.0.105'
PORT = 21567
BUFFSIZE = 1024
ADDR = (HOST,PORT)
lock = thread.allocate_lock()
class TronClient:
def __init__(self,control=None):
self.tcpSock = socket(AF_INET,SOCK_STREAM)
#self.tcpSock.settimeout(.2)
self.recvBuff = []
def connect(self):
self.tcpSock.connect(ADDR)
self.clientUID = self.tcpSock.recv(BUFFSIZE)
print 'My clientUID is ', self.clientUID
t = Thread(target = self.receiveFromSrv())
t.setDaemon(1)
t.start()
print 'going to main loop'
self.mainLoop()
#t = Thread(target = self.mainLoop())
#t.setName('mainLoop')
#t.setDaemon(1)
#t.start()
def receiveFromSrv(self):
RECIEVING = 1
while RECIEVING:
#print 'Attempting to retrieve more data'
#lock.acquire()
#print 'Lock Aquired in recieveFromSrv'
#try:
data = self.tcpSock.recv(BUFFSIZE)
#except socket.timeout,e:
#print 'Error recieving data, ',e
#continue
#print data
if not data: continue
header = data[:6]
msgType,msgLength,clientID = unpack("hhh",header)
print msgType
print msgLength
print clientID,'\n'
msg = data[6:]
while len(msg) < msgLength:
data = self.tcpSock.recv(BUFFSIZE)
dataLen = len(data)
if dataLen <= msgLength:
msg += data
else:
remLen = msgLength-len(data) #we just need to retrieve first bit of data to complete msg
msg += data[:remLen]
self.recvBuff.append(data[remLen:])
print msg
#else:
#lock.release()
# print 'lock release in receiveFromSrv'
#time.sleep(2)
#RECIEVING = 0
def disconnect(self,data=''):
self.send(DISCONNECT_REQUEST,data)
#self.tcpSock.close()
def send(self,msgType,msg):
header = pack("hhh",msgType,len(msg),self.clientUID)
msg = header+msg
self.tcpSock.send(msg)
def mainLoop(self):
while 1:
try:
#lock.acquire()
#print 'lock aquired in mainLoop'
data = raw_input('> ')
except EOFError: # enter key hit without any data (blank line) so ignore and continue
continue
#if not data or data == '': # no valid data so just continue
# continue
if data=='exit': # client wants to disconnect, so send request to server
self.disconnect()
break
else:
self.send(TRON_CHAT,data)
#lock.release()
#print 'lock released in main loop'
#self.recieveFromSrv()
#data = self.tcpSock.recv(BUFFSIZE)
#t = Thread(target = self.receiveFromSrv())
#t.setDaemon(1)
#t.start()
if __name__ == "__main__":
cli = TronClient()
cli.connect()
#t = Thread(target = cli.connect())
#t.setName('connect')
#t.setDaemon(1)
#t.start()
The server (uses a lock when incrementing or decrementing number of clients):
from socket import *
from threading import *
import thread
from controller import *
from networklingo import *
from struct import pack,unpack
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
nclntlock = thread.allocate_lock()
class TronServer:
def __init__(self,maxConnect=4,control=None):
self.servSock = socket(AF_INET,SOCK_STREAM)
# ensure that you can restart server quickly when it terminates
self.servSock.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
self.servSock.bind(ADDR)
self.servSock.listen(maxConnect)
# keep track of number of connected clients
self.clientsConnected = 0
# give each client a unique identfier for this run of server
self.clientUID = 0
# list of all clients to cycle through for sending
self.allClients = {}
# keep track of threads
self.cliThreads = {}
#reference back to controller
self.controller = control
self.recvBuff = []
def removeClient(self,clientID,addr):
if clientID in self.allClients.keys():
self.allClients[clientID].close()
print "Disconnected from", addr
nclntlock.acquire()
self.clientsConnected -= 1
nclntlock.release()
del self.allClients[clientID]
else:
print 'ClientID is not valid'
def recieve(self,clientsock,addr):
RECIEVING = 1
# loop serving the new client
while RECIEVING: # while PLAYING???
try:
data = clientsock.recv(BUFSIZE)
except:
RECIEVING = 0
continue
# if not data: break #no data was recieved
if data != '':
print 'Recieved msg from client: ',data
header = data[:6]
msgType,msgLength,clientID = unpack("hhh",header)
print msgType
print msgLength
print clientID,'\n'
if msgType == DISCONNECT_REQUEST: #handle disconnect request
self.removeClient(clientID,addr)
else: #pass message type and message off to controller
msg = data[6:]
while len(msg) < msgLength:
data = self.tcpSock.recv(BUFSIZE)
dataLen = len(data)
if dataLen <= msgLength:
msg += data
else:
remLen = msgLength-len(data) #we just need to retrieve first bit of data to complete msg
msg += data[:remLen]
self.recvBuff.append(data[remLen:])
print msg
# echo back the same data you just recieved
#clientsock.sendall(data)
self.send(TRON_CHAT,msg,-1) #send to client 0
for k in self.allClients.keys():
if self.allClients[k] == clientsock:
self.removeClient(k,addr)
print 'deleted after hard exit from clientID ', k
#self.cliThreads[k].join()
#del self.cliThreads[k]
# then tell controller to delete player with k
break
def send(self,msgType,msg,clientID=-1):
header = pack("hhh",msgType,len(msg),clientID)
msg = header+msg
if clientID in self.allClients:
self.allClients[clientID].send(msg)
elif clientID==ALL_PLAYERS:
for k in self.allClients.keys():
self.allClients[k].send(msg)
def mainLoop(self):
global nclntlock
try:
while self.controller != None and self.controller.state == WAITING:
print 'awaiting connections'
clientsock, caddy = self.servSock.accept()
nclntlock.acquire()
self.clientsConnected += 1
nclntlock.release()
print 'Client ',self.clientUID,' connected from:',caddy
clientsock.setblocking(0)
clientsock.send(str(self.clientUID))
self.allClients[self.clientUID] = clientsock
t = Thread(target = self.recieve, args = [clientsock,caddy])
t.setName('recieve-' + str(self.clientUID))
self.cliThreads[self.clientUID] = t
self.clientUID += 1
# t.setDaemon(1)
t.start()
finally:
self.servSock.close()
if __name__ == "__main__":
serv = TronServer(control = LocalController(nPlayers = 3, fWidth = 70, fHeight = 10))
t = Thread(target = serv.mainLoop())
t.setName('mainLoop')
# t.setDaemon(1)
t.start()
I think you want to try and set the socket to non-blocking mode:
http://docs.python.org/library/socket.html#socket.socket.setblocking
Set blocking or non-blocking mode of
the socket: if flag is 0, the socket
is set to non-blocking, else to
blocking mode. Initially all sockets
are in blocking mode. In non-blocking
mode, if a recv() call doesn’t find
any data, or if a send() call can’t
immediately dispose of the data, a
error exception is raised; in blocking
mode, the calls block until they can
proceed. s.setblocking(0) is
equivalent to s.settimeout(0);
s.setblocking(1) is equivalent to
s.settimeout(None).
Also, instead of using raw sockets, have you considdered using the multiprocessing module. It is a higher-level abstraction for doing network IO. The section on Pipes & Queues is specific to sending and receiving data between a client/server.