I'm trying to use sockets in python. For now, I'm trying to get it such that if any client sends any message it is received at all clients. However I'm getting very weird results. I think it's because I'm using multiple threads. The output of the program changes every time I run it. Is this a threading problem or is it something else?
import socket
import sys
from thread import *
from server import Server
from client import Client
s = Server()
start_new_thread(s.acceptConnection,())
m = Client("m")
k = Client("k")
start_new_thread(m.recieveData,())
start_new_thread(k.recieveData,())
k.sendData("Hey!")
print "*"*100
print repr(k.data()), repr(m.data())
print "*"*100
m.sendData("okay okay")
print "*"*100
print repr(k.data()), repr(m.data())
print "*"*100
m.client.close()
k.client.close()
s.s.close()
Server Class:
import socket
import sys
from thread import *
class Server(object):
def __init__(self,port = 5555):
self.host = 'localhost' # '' means connect to all hosts
self.port = port
self.text = ""
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
self.s.bind((self.host, self.port))
except socket.error as e:
print(str(e))
self.s.listen(2)
print "Waiting for a connection.\n"
self.connections = []
def threaded_client(self,conn):
# conn.send("Connected to server\n")
while True:
try:
data = conn.recv(2048)
except:
data = ""
if(not data):
break
# conn.sendall(reply)
for c,a in self.connections:
try:
c.sendall(data + "\n")
except:
print "connection lost\n"
self.connections.remove((c,a))
conn.close()
def acceptConnection(self):
while True:
conn, addr = self.s.accept()
self.connections += [(conn,addr)]
start_new_thread(self.threaded_client,(conn,))
Client class:
import socket
import sys
from thread import *
class Client(object):
def __init__(self,name):
self.host = 'localhost'
self.port = 5555
self.name = name
self.client= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect((self.host,self.port))
self.text = ""
def sendData(self,data):
self.client.send(data)
def recieveData(self):
while True:
try:
data = self.client.recv(2048)
except:
break
if data:
self.text = data
self.client.close()
def data(self):
return self.text
def closeClient(self):
self.client.close()
Anyway you have no warrants about the data was already come back to the clients when you try to print it. You should introduce some Conditions and use wait() and notifyAll() to make sure the data was arrive.... To check if my guess is correct put some sleep() in your test:
import time
k.sendData("Hey!")
print "*"*100
time.sleep(200)
print repr(k.data()), repr(m.data())
print "*"*100
m.sendData("okay okay")
print "*"*100
time.sleep(200)
print repr(k.data()), repr(m.data())
print "*"*100
If it works you should use conditions and notify to do your tests.
Moreover you must protect data access by a Lock().
def recieveData(self):
while True:
try:
data = self.client.recv(2048)
except:
break
if data:
self.l.acquire()
self.text = data
self.l.release()
self.client.close()
def data(self):
self.l.acquire()
ret = self.text
self.l.release()
return ret
Where attribute l of clients are defined in __init__ by
self.l=threading.Lock()
Related
I am fairly new to Python network programming. Recently I am trying to achieve make two programs talk to each other(i.e., send and receive information bi-laterally).
In program A, I have:
server_ip = ('', 4001)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(server_ip)
while True:
#continuously send and receive info to program B until some breaking condition reached
server.sendto(json.dumps(some_data).encode("utf-8"), server_ip)
recv_data = server.recv(1024)
# ...
In Program B, I have:
ADDR=('', 4001)
class Task()
"""
"""
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print('trying to connect to XXX')
while True:
try:
self.client.connect(ADDR)
break
except:
pass
print('connected to XXX')
def step(self):
"""
This method will be called repeatedly
"""
#...
self.send_udp_data()
self.get_data()
def send_udp_data(self):
#...
self.client.sendall(bytes(control_cmd, encoding='utf-8'))
print("Sending CMD")
def get_data(self):
while True:
try:
data = self.client.recv(10240)
data = bytearray(data)
data_dict=json.loads(data.decode('utf-8'))
except Exception as e:
#some error handling
I got countless errors while trying to achieve aforementioned functionality. How can I ensure these two programs properly communicate to each other?
This works:
Program A:
import json
import socket
ADDR_A = ('', 4001)
ADDR_B = ('', 4002)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(ADDR_A)
while True:
#continuously send and receive info to program B until some breaking condition reached
print("A sending...")
some_data = "This is some data sent by A"
# Note: this will be silently dropped if the client is not up and running yet
# And even if the the client is running, it may still be silently dropped since UDP is unreliable.
sock.sendto(json.dumps(some_data).encode("utf-8"), ADDR_B)
print("A receiving...")
recv_data = sock.recv(1024)
print(f"A received {recv_data}")
Program B:
import json
import socket
ADDR_A = ('', 4001)
ADDR_B = ('', 4002)
class Task():
"""
"""
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind(ADDR_B)
def step(self):
"""
This method will be called repeatedly
"""
print("B step")
self.send_data()
self.receive_data()
def send_data(self):
control_cmd = "This is a control command sent by B"
print("B sending...")
self.sock.sendto(bytes(control_cmd, encoding='utf-8'), ADDR_A)
print(f"B sent {control_cmd}")
def receive_data(self):
try:
data = self.sock.recv(10240)
print(f"B received raw data {data}")
data = bytearray(data)
data_dict=json.loads(data.decode('utf-8'))
print(f"B received JSON {data_dict}")
except Exception as e:
print(f"B exception {e} in receive_data")
task = Task()
while True:
task.step()
I implemented a simple network 'game' in Python - server draws a random number, and then the client tries to guess it. My application works great, when the client guesses the number, it disconnects from server (it is handled on client's side).
However, after the proper guess, the number is still the same. I would like to modify the application, such that when the client guesses the number, the server should then rand a new number, so other clients should guess the new one. How can I do this?
Some template, just to draw an attention to the problem:
#!/usr/bin/env python
from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys
class Handler(threading.Thread):
def __init__(self, connection, randomnumber):
threading.Thread.__init__(self)
self.connection = connection
self.randomnumber = randomnumber
def run(self):
while True:
try:
data = self.connection.recv(1024)
if data:
print data
try:
num = int(data)
if Server.guess(num) :
msg = "You won! This is the right number!"
self.connection.send(msg)
break
else :
msg = "Try again!"
self.connection.send(msg)
except ValueError, e:
msg = "%s" % e
self.connection.send(msg)
else:
msg = "error"
self.connection.send(msg)
except socket.error:
self.connection.close()
break
self.connection.close()
class Server:
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server_socket = None
self.randnum = randint(1, 100)
#classmethod
def guess(cls, no):
if cls.randnum == no:
cls.randnum = randint(1, 1000)
result = True
else:
result = False
return reslut
def run(self):
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.ip, self.port))
self.server_socket.listen(10)
print 'Num is %s' % self.randnum
while True:
connection, (ip, port) = self.server_socket.accept()
c = Handler(connection, self.randnum)
c.start()
except socket.error, e:
if self.server_socket:
self.server_socket.close()
sys.exit(1)
if __name__ == '__main__':
s = Server('127.0.0.1', 1234)
s.run()
Generate the random number that is shared between both server and all the client, there should be only instance of this, hence this should be class attribute.
Add a class function guess which return False upon incorrect guess and upon correct guess changes the randnum and returns True
class Server:
randnum = randint(1, 1000) # class attribute created
#classmethod
def guess(cls, no): # To be used "guess" if `no` attribute if the same as `cls.randnum`
if cls.randnum == no:
cls.randnum = randint(1, 1000)
result = True
else:
result = False
return result
def __init__(self, ip, port):
# ...
The client should call this Server.guess function each time.
Actually your issue comes from the fact that you create randnum as an instance method (see your self.randnum) as #shanmuga explained, if you simply declare it as being a class attribute, and remove the instance method it solves your issue (i.e. declaring it in the class directly).
As a side issue (not being an expert on socket), when you send message to the client, you might want to encode them as a byte object (in the run method of Handler, I changed self.connection.send(msg) to self.connection.send(msg.encode())). Also note that I used Python 3.6 (which mainly change the style of print statements)
See the code below:
#!/usr/bin/env python
from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys
class Handler(threading.Thread):
def __init__(self, connection, randomnumber):
threading.Thread.__init__(self)
self.connection = connection
self.randomnumber = randomnumber
def run(self):
while True:
try:
data = self.connection.recv(1024)
if data:
print(data)
try:
num = int(data)
if Server.guess(num) :
msg = "You won! This is the right number!"
self.connection.send(msg.encode())
break
else :
msg = "Try again!"
self.connection.send(msg.encode())
except ValueError as e:
msg = "%s" % e
self.connection.send(msg.encode())
else:
msg = "error"
self.connection.send(msg.encode())
except socket.error:
self.connection.close()
break
self.connection.close()
class Server:
randnum = randint(1,100)
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server_socket = None
#classmethod
def guess(cls, no):
if cls.randnum == no:
cls.randnum = randint(1, 1000)
print("New number is ", cls.randnum )
result = True
else:
result = False
return result
def run(self):
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.ip, self.port))
self.server_socket.listen(10)
print('Num is %s' % self.randnum)
while True:
connection, (ip, port) = self.server_socket.accept()
c = Handler(connection, self.randnum)
c.start()
except socket.error as e:
if self.server_socket:
self.server_socket.close()
sys.exit(1)
if __name__ == '__main__':
s = Server('127.0.0.1', 1234)
s.run()
I have set up a socket server with a client and a host.
It works fine until the client has disconnected, with both .shutdown() and .close().
When I then launch the client again, it can't connect.
I presume this is not because of how I've written my code but rather what I haven't written.
How do I make the server truly disconnect the client's connection so that it can connect again?
Server:
import socket, threading, time, json
ONLINE_USERS = []
SESSION = None
class User():
def __init__(user, connection, address):
print('for', address, '{Connection established}')
user.connection = connection
user.address = address
user.character = None
threading.Thread(target=user.process, args=(), daemon=True).start()
def process(user):
time.sleep(1)
user.send("&pLogin\n^^^^^\n")
username = user.send("&iUser>")
password = user.send("&iPass>")
print(user.ping())
print(user.logout())
def send(user, *x):
user.connection.sendall(str.encode(str(x)))
data = user.connection.recv(1024)
return data if data!=b'\x01' else True
def recv(user, x):
user.connection.recv(x)
def ping(user):
start = time.time()
user.connection.sendall(b'\x02')
end = float(user.connection.recv(1024))
return round((end - start) * 1000)
def logout(user):
user.connection.sendall(b'\x04')
return user.connection.recv(4)
class Session():
def __init__(session, host='', port=12345):
session.host = host
session.port = port
session.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
session.socket.bind((host, port))
session.socket.listen(10)
def accept():
conn = User(*session.socket.accept())
session.thread_accept = threading.Thread(target=accept, args=(), daemon=True).start()
def shutdown():
for user in ONLINE_USERS.keys():
ONLINE_USERS[user].connection.sendall(bytes([0xF]))
if __name__ == '__main__':
SESSION = Session()
input('Press heart to continue!\n')
Client:
import socket, sys, threading, time, os
def clear(t=0.5):
time.sleep(t)
os.system('cls')
def tryeval(x, default):
try:
return eval(x)
except:
return default
class Client():
def __init__(client):
try:
server_info = input('IP_ADDRESS:PORT>').split(':')
client.host = server_info[0]
client.port = int(server_info[1])
except:
client.host = 'localhost'
client.port = 12345
client.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.socket.settimeout(10)
try:
client.socket.connect((client.host, client.port))
clear()
client.data_exchange()
finally:
client.shutdown()
def data_exchange(client):
while True:
data = client.socket.recv(1024)
if data:
if data==b'\x02':
client.socket.sendall(str.encode(str(time.time())))
elif data==b'\x04':
client.shutdown()
else:
data = tryeval(data, ())
response = []
for item in data:
try:
prefix, content = item[:2], item[2:]
if prefix=='&p':
print(content, end='')
elif prefix=='&i':
response.append(input(content))
if prefix=='&c':
time.sleep(float(content))
clear()
except:
pass
if len(response)>0:
client.socket.sendall(str.encode(str(tuple(response))))
else:
client.socket.sendall(b'\x01')
time.sleep(0.001)
def shutdown(client):
try:
client.socket.sendall(b'\x04')
except:
pass
print('Shutting down program.')
client.socket.shutdown(socket.SHUT_RDWR)
print('Socket has been shutdown.')
client.socket.close()
print('Socket has been closed.')
print('Exiting program')
time.sleep(1)
sys.exit()
if __name__ == '__main__':
client = Client()
"The server repeatedly calls accept waiting for new incoming connections." No it doesn't. It calls accept once in a thread...which exits. – Mark Tolonen
self.handlers.append(ConnHandler(sock, self.handlers))I'm new to python and I tried to write a simple socket server to test stuff out and get to know the language better.
import asyncore
import socket
import json
class ConnHandler(asyncore.dispatcher_with_send):
def __init__(self, conn, handlerlist):
asyncore.dispatcher_with_send.__init__(self, conn)
self.handlers = handlerlist
def handle_close(self):
self.close()
print 'Socket closed'
if(self.handlers.count(self) > 0):
self.handlers.remove(self);
def handle_read(self):
data = ''
more = True
while more:
try:
data += self.recv(1024)
except socket.error, e:
more = False
if data == '':
return
try:
message = json.loads(data)
except ValueError:
self.send('Invalid JSON\n')
return
print message
class TestServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
self.handlers = []
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print 'Incoming connection from %s' % repr(addr)
self.handlers.append(ConnHandler(sock, self.handlers))
def sendToAll(self, string):
for h in self.handlers:
h.send(string + '\n')
server = TestServer('localhost', 55555)
asyncore.loop()
My problem is the following.
If I connect to the server with telnet and then quit telnet to close the connection, python just spams 'Socket closed' in the terminal. How can I fix this? Are there obvious beginner mistakes in the above code?
handle_close is not meant to detect if peer is disconnected, you get this information in handle_read if .recv call returns an empty string. Then you can close the socket, and then handle_close is called.
Here is a modified version of your code:
def handle_close(self):
print 'Socket closed'
if(self.handlers.count(self) > 0):
self.handlers.remove(self);
def handle_read(self):
data = ''
more = True
while more:
try:
new_data = self.recv(1024)
if not new_data:
self.close()
return
else:
data += new_data
except socket.error, e:
more = False
if data == '':
return
try:
message = json.loads(data)
except ValueError:
self.send('Invalid JSON\n')
return
print message
I am attempting to write a UDP chat system, but for some reason the listen() loop is not working and I can not figure out why.
import socket
import json
import landerdb
import threading
class PeerChat:
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.db = landerdb.Connect("nodes")
self.brok_ip = ""
self.brok_port = 5000
def listen(self):
while True:
msg = self.sock.recv(1024)
print msg
def main(self):
while True:
msg = raw_input("> ")
for x in self.db.find("nodes", "all"):
self.sock.sendto(msg, tuple(x['addr']))
def GetNodes(self):
self.sock.sendto("as", (self.brok_ip, self.brok_port))
with open("nodes", 'wb') as file:
msg, addr = self.sock.recvfrom(1024)
print msg
file.write(msg)
if __name__ == "__main__":
PeerChat().GetNodes()
threading.Thread(target=PeerChat().listen).start()
PeerChat().main()