How to add visuals to python chat program - python

I have written a basic python socket based chat program (My second one) and i would like to add some visuals to make it a little more user friendly.
Should I layer the visuals over the existing program or should i make a new program around the visuals
What python module should i use for the visuals (i know pygame is that suitable)
Can i have some form of general idea on how to write this (Code examples maybe?)
Here is my existing code:
Client:
import socket, threading
#Setup The Variables
WindowTitle = 'Chat 2.0 - Client'
s = socket.socket()
host = raw_input("Please Enter External IP adress Here: ")
print
host = socket.gethostname()
port = 8008
#Attempted To Connect
print "Conecting..."
print
while True:
try:
s.connect((host, port))
break
except:
pass
print "Connected To " + str(host) + " " + str(port)
print
#Check For Incomming Data
def check_for_data():
while True:
data = s.recv(1024)
if data:
print
print "Other: " + str(data)
print
print "You: "
else:
print "Client closed connection"
s.close()
break
#Send Data
def send_data():
while True:
user_input = raw_input("You: ")
print
s.sendall(user_input)
#Start Threads \ Main Loop
t = threading.Thread(target=send_data)
t.daemon = True
t.start() #1
check_for_data()
s.close
Server:
import socket, threading
#Setup The Variables
WindowTitle = 'Chat 2.0 - Client'
host = socket.gethostname()
port = 8008
s = socket.socket()
s.bind((host, port))
print "Awaiting Connection..."
print
s.listen(5)
c, addr = s.accept()
print "Connection From: " + str(addr)
print
def check_for_data(c):
while True:
data = c.recv(1024)
if data:
print
print "Other: " + str(data)
print
print "You: "
else:
print "Client closed connection"
c.close()
break
def send_data():
while True:
message = raw_input("You: ")
print
c.sendall(message)
#Start Threads \ Main Loop
t = threading.Thread(target=send_data)
t.daemon = True
t.start() #1
check_for_data(c)
c.close()

Have to agree that tkinter is probably the better way to go here. For a chat program, pygame's sprites/rects/surfaces all have little use. However, tkinter has buttons and labels and other similar things built in that would suit your needs a bit better. Btw, to make your life with socket easier, look into the makefile method. The makefile method allows for much easier use. I recommend looking at Socket.error [Error 10060] for a description of how to use it and its uses. It's not necessary, just makes life easier :)
Edit:
"Should I layer the visuals over the existing program or should i make a new program around the visuals"
Not quite sure what you mean here by "existing program." When it comes to what you should code, split up your logic and user interface stuff. So have a module that handles the sending and receiving of messages, and another that handles the display.
"What python module should i use for the visuals (i know pygame is that suitable)"
Probably tkinter. I only have experience in tkinter and pygame, but of the two, you probably want tkinter for this. I explained why in the first paragraph.
"Can i have some form of general idea on how to write this (Code examples maybe?)"
Assuming you use tkinter, look into stringvars, they may or may not be useful for you. As for the structure of your program, I'm not exactly sure what you want so I can't help you there. But do start simple. For example, get messages to send between programs, and print them out. Then have the messages show up on a window.. Make a way for the user to type in message via GUI (look into tkinter entry widget!). Best of luck you!
Edit 2: To answer your question about how to position button. Here is some code from my last project where I had to use a button to do something.
button_frame = tkinter.Frame(master = self.option_window)
button_frame.grid(row = 5, column = 1)
ok_button = tkinter.Button(master = button_frame, text = 'OK',
font = DEFAULT_FONT, command = self.on_ok_clicked)
The position of the button is based off of where I did the button_frame.grid(....). To organize your tkinter window, I recommend using grid and not pack.
Oh, and self.option_window was a tkinter.Tk() object in my case.

Related

Python: Retrieve list of sockets on current machine?

I'm brand new to Python (as of last week) and I'm still getting to grips with the basics so please excuse any ignorance I display.
As part of my homework I have been asked to make a basic port scanner and one of the functions I have to include is the retrieval of a list of sockets on the current machine. I have been looking around and managed to piece together a piece of code that allows me to enter the IP of the machine I wish to scan but I want to try and make it so it automatically scans whichever machine it is running on.
elif (userChoice == "4"):
print("You selected " + userChoice)
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # s will be equal to the command looking for the IPV4 addresses
except socket.error:
sys.exit("Failed to create socket.") # error handling message to be printed to the console should a socket failed to be created
print("Socket created")
hostAddress = input("Please enter host address to scan - example 'www.server.com': ")
print ("You entered " + hostAddress )
try:
remoteIP = socket.gethostbyname(hostAddress)
except socket.gaierror:
sys.exit("Hostname could not be resolved exiting")
ret = input("Hit return to go back to the menu")
continue
print("IP address of " + hostAddress + ' is ' + remoteIP)
This is my code so far. If anyone could help me out or tell me if I'm even going in the right direction with this I would be very grateful.
Also, with me being a noob, if anyone has any suggestions for good reading materials to help me get to get to grips with the basics I would very much appreciate it.
Thanks.
To check open ports on remote server-
# For input hostAddress
remoteIP = socket.gethostbyname(hostAddress)
for port in range(1,1025):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((remoteIP, port))
if result == 0:
print("Port %s: Open"%port)
sock.close()
=> Port 80: Open

Problems with a chat program written in Python and PyGTK

I am new to python and I am currently working on a chat room program in Python (still in progress...). I have also made a GUI for my program. Initially, I made two py files, one for the GUI and one for the chatting function. They both worked perfectly when separated. After, I combined the two files. I faced the following two problems:
One of my threads (target = loadMsg) is used to wait for the host's msg and print it out on the screen. The problem is that it delays for one msg every time. For example, I sent a "1" to the host and the host should return a "1" immediately. But, the "1" I received didn't appear on my screen. Then I send a "2" to the host and the host should reply a "2" immediately. Then, my screen shows a "1" but the "2" is still missing until the host reply a "3" to me, after I send a "3" to the host. Where is the problem?
This is a technical problem. I was testing the stability of the chat room and I found that about 10% of my msg disappeared during the transmission and this situation occurs randomly. How can I fix such a problem?
Sorry for my poor English. I hope someone can help me with it.T_T
Here is my code for your reference:
---Client
import pygtk,gtk
import logging
from threading import *
import socket
DEBUG = 1
HOST = ''
PORT = 8018
TIMEOUT = 5
BUF_SIZE = 1024
class Base():
def reload(self):
try:
buf = self.sock.recv(BUF_SIZE)
print buf
self.addMsg(buf)
except:
pass
def reload_butt(self,widget):
try:
self.thread = Thread(target=self.reload)
self.thread.start()
except:
pass
def loadMsg(self):
try:
while True :
buf = self.sock.recv(BUF_SIZE)
print buf
self.addMsg(buf)
except:
self.sock.close()
def sendMsg(self,widget):
if DEBUG : print "Send Msg"
if self.entry.get_text() : self.sock.send(self.entry.get_text())
self.entry.set_text("")
def addMsg(self,string):
if DEBUG : print "Try to add Msg"
if self.entry.get_text() :
iter = self.buffer1.get_iter_at_offset(-1)
self.buffer1.insert(iter,("\n Username: "+string))
self.entry.set_text("")
self.adj = self.scrolled_window.get_vadjustment()
self.adj.set_value( self.adj.upper - self.adj.page_size )
if DEBUG : print "Add msg ok"
def destroy(self,widget):
if DEBUG : print "Destroy function called"
self.sock.close()
gtk.main_quit()
def __init__(self,sock):
if DEBUG : print "Initializing..."
self.sock = sock
self.win=gtk.Window()
self.win.connect("destroy",self.destroy)
self.vbox=gtk.VBox()
self.win.add(self.vbox)
self.view=gtk.TextView()
self.view.set_editable(False)
self.buffer1=self.view.get_buffer()
self.scrolled_window=gtk.ScrolledWindow()
self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
self.scrolled_window.add(self.view)
self.vbox.add(self.scrolled_window)
self.entry=gtk.Entry()
self.entry.connect("activate",self.sendMsg)
self.enter=gtk.Button("Enter")
self.enter.connect("clicked",self.sendMsg)
self.reload=gtk.Button("Reload")
self.reload.connect("clicked",self.reload_butt)
self.hbox=gtk.HBox()
self.hbox.add(self.entry)
self.hbox.pack_start(self.reload,False,False)
self.hbox.pack_start(self.enter,False,False)
self.vbox.pack_start(self.hbox,False,False)
self.win.show_all()
if DEBUG : print "Finish initializing"
def main(self):
try :
gtk.main()
except :
print "Error!!!"
def main() :
try :
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
print ('Connecting to '+ str(HOST) +' ' + str(PORT))
base=Base(sock)
thread1=Thread(target=base.loadMsg)
thread2=Thread(target=base.main)
thread2.start()
thread1.start()
except :
print "Err0r!!!"
sock.close()
main()
---host (an echo host)
import socket
HOST = ''
PORT = 8018
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(5)
conn, addr = s.accept()
print 'Connected by', addr
try :
print "Start!"
while True:
data = conn.recv(1024)
print data
reply = data # echo
if not reply : break
if reply== "!q" :
conn.close()
break
conn.send(reply)
conn.close()
except :
print "Error!!!!!"
conn.close()
I would seriously recommend to use the gio library (part of glib). Using that library, you connect functions to the socket operations such as when data is available, or when data can be written to the socket. The library will call these function when necessary, and you don't need a wait loop. Which is more CPU-friendly.
http://jcoppens.com/soft/howto/gtk/chat_socket.php contains an example of communications between a C program and Python, using gio, which might be useful to you.
This way, you can start monitoring the sockets after the GUI has started, and you do not need threads to attend the communications.

Keep console input line below output

[EDIT:]
I'm currently trying to make a small tcp chat application. Sending and receiving messages already works fine... But the problem is:
When i start typing a message while i receive one... it appears after the text I'm writing
Screenshot: http://s7.directupload.net/images/140816/6svxo5ui.png
[User sent > "hello", then I started writing "i am writing..." then user wrote " i sent a..." before i sent my message... so it has been placed after my input...
I want the incoming message always to be before my input !
this is my current code:
Client.py
con = connect.User()
server = raw_input("Type in the server adress \n[leave blank to use xyr.no-ip.info]\n>:")
nick =""
while nick == "":
nick = raw_input("Type in your nickname\n>:")
con.connect(server, nick)
def sender():
print("Sender started")
while 1:
msg = raw_input()
if msg == "q":
break
con.send(msg)
con.disconnect()
def receiver(server):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
sock.connect((server, 8000))
sock.send("%pyreceiver\n")
print("Receiver started")
while 1:
msg_in = sock.recv(1024)
if not str(msg_in).startswith("[py]" + nick):
if str(msg_in).startswith("/ua"):
print(str(msg_in)[3:])
elif str(msg_in).startswith("/u "):
print(str(msg_in)[2:])
else:
print(str(msg_in[:-1]))
#
if nick == "":
nick = "guest"
print("Name changed to ""guest""")
time.sleep(.5)
thread.start_new_thread(receiver, (server, ))
time.sleep(.5)
thread.start_new_thread(sender())
Connect.py
import socket
import time
class User():
nickel =""
def connect(self, server="xyr.no-ip.info", nick="guest"):
nickel = nick
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
print("server changed to xyr.no-ip.info")
time.sleep(.5)
print("Connecting...")
self.sock.connect((server, 8000))
print("Connected")
time.sleep(.4)
self.sock.send("[py]" + nick + "\n")
self.sock.send(nick + " connected with a python client\n")
print("registered as " + nick)
time.sleep(.3)
def send(self, msg):
self.sock.send(msg + "\n")
def disconnect(self):
self.sock.close()
print("disconnected")
Your code writes everything to stdout. Whenever something arrives to either of your sender/receiver threads, it prints to stdout. The issue with that is, due to the fundamental nature of output streams, you cannot accomplish the following :
place incoming messages above the stuff currently being typed/echoed.
Things happen strictly in the order of occurrence. The moment something comes in, wherever the cursor is, the print statement dumps that data over there. You cannot modify that behaviour without using fancier / more powerful constructs.
In order to do what you want, I would use ncurses. You seem to be using python on Windows, so you're going to have to do some digging on how to get equivalent functionality. Check out this thread : Curses alternative for windows
I had a similar problem and I found that a simpler solution (for me) was to get input via readchar (https://github.com/magmax/python-readchar/tree/master/readchar).
Using readchar, I would buffer each keystroke (checking for key.BACKSPACE and CR - see code snippet below).
All output I would prepend with "/033[1A" (make the cursor move up), print the output line, and then a "/n"...
after each output line, I move the cursor to the beginning and re-print the self.input_buff
while the user is doing input, this handles console input, displaying what they are typing:
keypress = readkey()
if keypress == key.BACKSPACE:
self.input_buff = self.input_buff[:-1]
print("\033[0A%s " % self.input_buff)
continue
if keypress != key.CR:
self.input_buff = "%s%s" % (self.input_buff, keypress)
print("\033[0A%s" % self.input_buff)
continue
This kept the input line at the bottom and all terminal output above it.
I know it comes a year late and if you are a wiz with curses, maybe that is the way to go...

Implementing Multi-Threading in a Python Script

I wanted to create a python script to stress test my servers.
So I created this basic UDP flooder and I think I have it working correctly.
My question is how would I go about adding multi-threading to this?
I read a manual on Python threading but didn't understand how to actually
implement it into my script.
import socket
import random
print "Target:",
ipaddr = raw_input()
sent = 1
bytes = random._urandom(10000)
port = 1
while sent > 0:
print "Test Started On", ipaddr, "|", sent, "Packets Sent. Press Ctrl+C To Stop."
sent += 1
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(bytes,(ipaddr,port))
port = random.randint(1, 65500)
raw_input()
If you extract the business part of your application into a function like:
def do_the_flooding():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(bytes,(ipaddr,port))
You can then call it in a thread:
import threading
t = threading.Thread(target=do_the_flooding)
t.start()

Thread synchronization in Python

I am currently working on a school project where the assignment, among other things, is to set up a threaded server/client system. Each client in the system is supposed to be assigned its own thread on the server when connecting to it. In addition i would like the server to run other threads, one concerning input from the command line and another concerning broadcasting messages to all clients. However, I can't get this to run as i want to. It seems like the threads are blocking each other. I would like my program to take inputs from the command line, at the "same time" as the server listens to connected clients, and so on.
I am new to python programming and multithreading, and allthough I think my idea is good, I'm not suprised my code doesn't work. Thing is I'm not exactly sure how I'm going to implement the message passing between the different threads. Nor am I sure exactly how to implement the resource lock commands properly. I'm going to post the code for my server file and my client file here, and I hope someone could help me with this. I think this actually should be two relative simple scripts. I have tried to comment on my code as good as possible to some extend.
import select
import socket
import sys
import threading
import client
class Server:
#initializing server socket
def __init__(self, event):
self.host = 'localhost'
self.port = 50000
self.backlog = 5
self.size = 1024
self.server = None
self.server_running = False
self.listen_threads = []
self.local_threads = []
self.clients = []
self.serverSocketLock = None
self.cmdLock = None
#here i have also declared some events for the command line input
#and the receive function respectively, not sure if correct
self.cmd_event = event
self.socket_event = event
def openSocket(self):
#binding server to port
try:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((self.host, self.port))
self.server.listen(5)
print "Listening to port " + str(self.port) + "..."
except socket.error, (value,message):
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def run(self):
self.openSocket()
#making Rlocks for the socket and for the command line input
self.serverSocketLock = threading.RLock()
self.cmdLock = threading.RLock()
#set blocking to non-blocking
self.server.setblocking(0)
#making two threads always running on the server,
#one for the command line input, and one for broadcasting (sending)
cmd_thread = threading.Thread(target=self.server_cmd)
broadcast_thread = threading.Thread(target=self.broadcast,args=[self.clients])
cmd_thread.daemon = True
broadcast_thread.daemon = True
#append the threads to thread list
self.local_threads.append(cmd_thread)
self.local_threads.append(broadcast_thread)
cmd_thread.start()
broadcast_thread.start()
self.server_running = True
while self.server_running:
#connecting to "knocking" clients
try:
c = client.Client(self.server.accept())
self.clients.append(c)
print "Client " + str(c.address) + " connected"
#making a thread for each clientn and appending it to client list
listen_thread = threading.Thread(target=self.listenToClient,args=[c])
self.listen_threads.append(listen_thread)
listen_thread.daemon = True
listen_thread.start()
#setting event "client has connected"
self.socket_event.set()
except socket.error, (value, message):
continue
#close threads
self.server.close()
print "Closing client threads"
for c in self.listen_threads:
c.join()
def listenToClient(self, c):
while self.server_running:
#the idea here is to wait until the thread gets the message "client
#has connected"
self.socket_event.wait()
#then clear the event immidiately...
self.socket_event.clear()
#and aquire the socket resource
self.serverSocketLock.acquire()
#the below is the receive thingy
try:
recvd_data = c.client.recv(self.size)
if recvd_data == "" or recvd_data == "close\n":
print "Client " + str(c.address) + (" disconnected...")
self.socket_event.clear()
self.serverSocketLock.release()
return
print recvd_data
#I put these here to avoid locking the resource if no message
#has been received
self.socket_event.clear()
self.serverSocketLock.release()
except socket.error, (value, message):
continue
def server_cmd(self):
#this is a simple command line utility
while self.server_running:
#got to have a smart way to make this work
self.cmd_event.wait()
self.cmd_event.clear()
self.cmdLock.acquire()
cmd = sys.stdin.readline()
if cmd == "":
continue
if cmd == "close\n":
print "Server shutting down..."
self.server_running = False
self.cmdLock.release()
def broadcast(self, clients):
while self.server_running:
#this function will broadcast a message received from one
#client, to all other clients, but i guess any thread
#aspects applied to the above, will work here also
try:
send_data = sys.stdin.readline()
if send_data == "":
continue
else:
for c in clients:
c.client.send(send_data)
self.serverSocketLock.release()
self.cmdLock.release()
except socket.error, (value, message):
continue
if __name__ == "__main__":
e = threading.Event()
s = Server(e)
s.run()
And then the client file
import select
import socket
import sys
import server
import threading
class Client(threading.Thread):
#initializing client socket
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.client_running = False
self.running_threads = []
self.ClientSocketLock = None
def run(self):
#connect to server
self.client.connect(('localhost',50000))
#making a lock for the socket resource
self.clientSocketLock = threading.Lock()
self.client.setblocking(0)
self.client_running = True
#making two threads, one for receiving messages from server...
listen = threading.Thread(target=self.listenToServer)
#...and one for sending messages to server
speak = threading.Thread(target=self.speakToServer)
#not actually sure wat daemon means
listen.daemon = True
speak.daemon = True
#appending the threads to the thread-list
self.running_threads.append(listen)
self.running_threads.append(speak)
listen.start()
speak.start()
#this while-loop is just for avoiding the script terminating
while self.client_running:
dummy = 1
#closing the threads if the client goes down
print "Client operating on its own"
self.client.close()
#close threads
for t in self.running_threads:
t.join()
return
#defining "listen"-function
def listenToServer(self):
while self.client_running:
#here i acquire the socket to this function, but i realize I also
#should have a message passing wait()-function or something
#somewhere
self.clientSocketLock.acquire()
try:
data_recvd = self.client.recv(self.size)
print data_recvd
except socket.error, (value,message):
continue
#releasing the socket resource
self.clientSocketLock.release()
#defining "speak"-function, doing much the same as for the above function
def speakToServer(self):
while self.client_running:
self.clientSocketLock.acquire()
try:
send_data = sys.stdin.readline()
if send_data == "close\n":
print "Disconnecting..."
self.client_running = False
else:
self.client.send(send_data)
except socket.error, (value,message):
continue
self.clientSocketLock.release()
if __name__ == "__main__":
c = Client((socket.socket(socket.AF_INET, socket.SOCK_STREAM),'localhost'))
c.run()
I realize this is quite a few code lines for you to read through, but as I said, I think the concept and the script in it self should be quite simple to understand. It would be very much appriciated if someone could help me synchronize my threads in a proper way =)
Thanks in advance
---Edit---
OK. So I now have simplified my code to just containing send and receive functions in both the server and the client modules. The clients connecting to the server gets their own threads, and the send and receive functions in both modules operetes in their own separate threads. This works like a charm, with the broadcast function in the server module echoing strings it gets from one client to all clients. So far so good!
The next thing i want my script to do, is taking specific commands, i.e. "close", in the client module to shut down the client, and join all running threads in the thread list. Im using an event flag to notify the listenToServer and the main thread that the speakToServer thread has read the input "close". It seems like the main thread jumps out of its while loop and starts the for loop that is supposed to join the other threads. But here it hangs. It seems like the while loop in the listenToServer thread never stops even though server_running should be set to False when the event flag is set.
I'm posting only the client module here, because I guess an answer to get these two threads to synchronize will relate to synchronizing more threads in both the client and the server module also.
import select
import socket
import sys
import server_bygg0203
import threading
from time import sleep
class Client(threading.Thread):
#initializing client socket
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.client_running = False
self.running_threads = []
self.ClientSocketLock = None
self.disconnected = threading.Event()
def run(self):
#connect to server
self.client.connect(('localhost',50000))
#self.client.setblocking(0)
self.client_running = True
#making two threads, one for receiving messages from server...
listen = threading.Thread(target=self.listenToServer)
#...and one for sending messages to server
speak = threading.Thread(target=self.speakToServer)
#not actually sure what daemon means
listen.daemon = True
speak.daemon = True
#appending the threads to the thread-list
self.running_threads.append((listen,"listen"))
self.running_threads.append((speak, "speak"))
listen.start()
speak.start()
while self.client_running:
#check if event is set, and if it is
#set while statement to false
if self.disconnected.isSet():
self.client_running = False
#closing the threads if the client goes down
print "Client operating on its own"
self.client.shutdown(1)
self.client.close()
#close threads
#the script hangs at the for-loop below, and
#refuses to close the listen-thread (and possibly
#also the speak thread, but it never gets that far)
for t in self.running_threads:
print "Waiting for " + t[1] + " to close..."
t[0].join()
self.disconnected.clear()
return
#defining "speak"-function
def speakToServer(self):
#sends strings to server
while self.client_running:
try:
send_data = sys.stdin.readline()
self.client.send(send_data)
#I want the "close" command
#to set an event flag, which is being read by all other threads,
#and, at the same time set the while statement to false
if send_data == "close\n":
print "Disconnecting..."
self.disconnected.set()
self.client_running = False
except socket.error, (value,message):
continue
return
#defining "listen"-function
def listenToServer(self):
#receives strings from server
while self.client_running:
#check if event is set, and if it is
#set while statement to false
if self.disconnected.isSet():
self.client_running = False
try:
data_recvd = self.client.recv(self.size)
print data_recvd
except socket.error, (value,message):
continue
return
if __name__ == "__main__":
c = Client((socket.socket(socket.AF_INET, socket.SOCK_STREAM),'localhost'))
c.run()
Later on, when I get this server/client system up and running, I will use this system on some elevator models we have here on the lab, with each client receiving floor orders or "up" and "down" calls. The server will be running an distribution algorithm and updating the elevator queues on the clients that are most appropriate for the requested order. I realize it's a long way to go, but I guess one should just take one step at the time =)
Hope someone has the time to look into this. Thanks in advance.
The biggest problem I see with this code is that you have far too much going on right away to easily debug your problem. Threading can get extremely complicated because of how non-linear the logic becomes. Especially when you have to worry about synchronizing with locks.
The reason you are seeing clients blocking on each other is because of the way you are using your serverSocketLock in your listenToClient() loop in the server. To be honest this isn't exactly your problem right now with your code, but it became the problem when I started to debug it and turned the sockets into blocking sockets. If you are putting each connection into its own thread and reading from them, then there is no reason to use a global server lock here. They can all read from their own sockets at the same time, which is the purpose of the thread.
Here is my recommendation to you:
Get rid of all the locks and extra threads that you don't need, and start from the beginning
Have the clients connect as you do, and put them in their thread as you do. And simply have them send data every second. Verify that you can get more than one client connecting and sending, and that your server is looping and receiving. Once you have this part working, you can move on to the next part.
Right now you have your sockets set to non-blocking. This is causing them all to spin really fast over their loops when data is not ready. Since you are threading, you should set them to block. Then the reader threads will simply sit and wait for data and respond immediately.
Locks are used when threads will be accessing shared resources. You obviously need to for any time a thread will try and modify a server attribute like a list or a value. But not when they are working on their own private sockets.
The event you are using to trigger your readers doesn't seem necessary here. You have received the client, and you start the thread afterwards. So it is ready to go.
In a nutshell...simplify and test one bit at a time. When its working, add more. There are too many threads and locks right now.
Here is a simplified example of your listenToClient method:
def listenToClient(self, c):
while self.server_running:
try:
recvd_data = c.client.recv(self.size)
print "received:", c, recvd_data
if recvd_data == "" or recvd_data == "close\n":
print "Client " + str(c.address) + (" disconnected...")
return
print recvd_data
except socket.error, (value, message):
if value == 35:
continue
else:
print "Error:", value, message
Backup your work, then toss it - partially.
You need to implement your program in pieces, and test each piece as you go. First, tackle the input part of your program. Don't worry about how to broadcast the input you received. Instead worry that you are able to successfully and repeatedly receive input over your socket. So far - so good.
Now, I assume you would like to react to this input by broadcasting to the other attached clients. Well too bad, you can't do that yet! Because, I left one minor detail out of the paragraph above. You have to design a PROTOCOL.
What is a protocol? It's a set of rules for communication. How does your server know when the client had finished sending it's data? Is it terminated by some special character? Or perhaps you encode the size of the message to be sent as the first byte or two of the message.
This is turning out to be a lot of work, isn't it? :-)
What's a simple protocol. A line-oriented protocol is simple. Read 1 character at a time until you get to the end of record terminator - '\n'. So, clients would send records like this to your server --
HELO\n
MSG DAVE Where Are Your Kids?\n
So, assuming you have this simple protocol designed, implement it. For now, DON'T WORRY ABOUT THE MULTITHREADING STUFF! Just worry about making it work.
Your current protocol is to read 1024 bytes. Which may not be bad, just make sure you send 1024 byte messages from the client.
Once you have the protocol stuff setup, move on to reacting to the input. But for now you need something that will read input. Once that is done, we can worry about doing something with it.
jdi is right, you have too much program to work with. Pieces are easier to fix.

Categories