I need to test a device update function. The function opens a socket on a host and sends a block of text.
The update can take up to 120 seconds. It returns a code for success/failure. To allow continued functioning of the program the update is launched in a thread.
I cannot control the response of the device. The simulation needs to be able to hold an open connection for at least 120 seconds.
It does not need to be safe or scalable since it will only be used for an integration test. The simplest solution is preferred. Pure python is best, but a docker is also acceptable.
I wrote this up based on rdas's pointer.
import json
import logging
import socket
import socketserver
import threading
import time
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
class LongRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
# Echo the back to the client
data = json.loads(self.request.recv(1024).decode())
t = 0
while t < data['delay']:
time.sleep(1)
print(".", end='')
t += 1
if t % 80 == 0:
print("\n")
print("\n")
self.request.send(b"ok")
class Server():
def __init__(self, host='localhost', port=0):
self.host = host
self.port = port
self.ip = None
self.server = None
def run(self):
address = (self.host, self.port) # let the kernel assign port if port=0
self.server = socketserver.TCPServer(address, LongRequestHandler)
self.ip, self.port = self.server.server_address # what port was assigned?
t = threading.Thread(target=self.server.serve_forever)
t.setDaemon(True) # don't hang on exit
t.start()
return True
def send_request(self, data: dict ):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.ip, self.port))
message = json.dumps(data).encode()
s.send(message)
response = s.recv(1024)
s.close()
return response
def __exit__(self):
self.server.shutdown()
self.server.socket.close()
if __name__ == '__main__':
# For simple testing and config example...
server = Server()
server.run()
# Send the data
d = dict(delay=5) # set delay here to desired
out = server.send_request(d)
print('Received: {!r}'.format(out))
Related
Okay, so I createda socket server in python and I want when someone connects to it to run an application on the sever but which is user controlled. I'll try to explain better with the code.
#!/usr/bin/python
import socket
import select
import os
from time import sleep
class SocketServer:
""" Simple socket server that listens to one single client. """
def __init__(self, host = '0.0.0.0', port = 2010):
""" Initialize the server with a host and port to listen to. """
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.host = host
self.port = port
self.sock.bind((host, port))
self.sock.listen(1)
def close(self):
""" Close the server socket. """
print('Closing server socket (host {}, port {})'.format(self.host, self.port))
if self.sock:
self.sock.close()
self.sock = None
def run_server(self):
""" Accept and handle an incoming connection. """
print('Starting socket server (host {}, port {})'.format(self.host, self.port))
client_sock, client_addr = self.sock.accept()
print('Client {} connected'.format(client_addr))
stop = False
while not stop:
if client_sock:
# Check if the client is still connected and if data is available:
os.system("python vuln.py")
# try:
# rdy_read, rdy_write, sock_err = select.select([client_sock,], [], [])
# except select.error:
# print('Select() failed on socket with {}'.format(client_addr))
# return 1
if len(rdy_read) > 0:
read_data = client_sock.recv(255)
if len(read_data) == 0:
print('{} closed the socket.'.format(client_addr))
stop = True
else:
print('>>> Received: {}'.format(read_data.rstrip()))
if read_data.rstrip() == 'quit':
stop = True
else:
client_sock.send(read_data)
else:
print("No client is connected, SocketServer can't receive data")
stop = True
# Close socket
print('Closing connection with {}'.format(client_addr))
client_sock.close()
return 0
def main():
server = SocketServer()
while (True):
server.run_server()
print 'Exiting'
if __name__ == "__main__":
main()
This is my socket server, which always runs and cand establish multiple connections.
print("Please tell me what's your age")
age = input('> ')
sleep(1)
print("Damn man, sometimes I wish I was %s" % age)
sleep(1)
and this is the app which I want to run on the server and let the user who connects with netcat for example see the same prompt and have the same functionality but on the server.
I have a code below that does the client-server communication properly.
The client:
# Client
import socket
import pickle
class Model:
def __init__(self, host, port):
self.port = port
self.host = host
def snd_query(self, query):
received_data = []
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((self.host, self.port))
sock.sendall(pickle.dumps(query))
while True:
packet = sock.recv(4096)
if not packet or packet == b'':
break
received_data.append(packet)
try:
content = pickle.loads(b"".join(received_data))
return content
except EOFError:
return None
and a server:
# Server.py
import socketserver
import pickle
import configparser
from data_manipulation import DataManipulation
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
db = DataManipulation("data.db")
request = pickle.loads(self.request.recv(1024))
if request['command'] == 'GET':
content = db.get_data()
#elif ...:
#... some other logic and database interactions
self.request.sendall(pickle.dumps((content)))
def main(HOST, PORT):
try:
my_server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
my_server.serve_forever()
except KeyboardInterrupt:
my_server.shutdown()
my_server.server_close()
if __name__ == "__main__":
config = configparser.ConfigParser()
config.read('../params.ini')
main(config['SERVER']['host'], int(config['SERVER']['port']))
In that form with every new handled request a database connection db instance is created.
I would like to avoid it. I would like to make db object ones and raise it with argument read from ini file. Obviously it is enough to read it once.
All examples that I found show simple echo server application. handle() doesn't do much, only prints some stuff.
I am not sure where is the correct place to call db object to have only one instance?
How to properly incorporate some advanced logic in handle() method?
I am working on UDP chat which should be listening and being able to send message any time using only one socket. Example, I will have the chat program done, I will open it first time, then second time and I must be able to communicate over UDP from both programs, simply each program has only one opened socket.
My two threads are for listening, which is deamon thread, because I want it to listen to new messages nonstop, and my other is sending the messages, which is just like a normal thread.
First of all, my problem is that it looks like my threads are blocking each other, because if I run the program, I only get output from the first thread I start.
Second problem is that I am not sure if my sending function or the entire class is written properly, or if there is something missing or incorrect.
Thanks in advance. Btw, I am new into python and I am using python 3, just to make it clear.
import socket
import threading
import logging
import time
from sys import byteorder
class Sending():
def __init__(self, name, tHost, tPort):
self.name = name
self.host = tHost
self.port = tPort
def set_name(self, name):
self.name = name
def send(self, name, tHost, tPort, msgType, dgramSize):
logging.debug('Starting send run')
message = input('Enter message: ')
data = bytearray()
data.extend( (name.encode('utf-8'), message.encode('utf-8'), msgType.to_bytes(1, byteorder = 'little')) )
#data.extend(message.encode(encoding='utf_8'))
self.sock.sendto(bytearray(data), (tHost, tPort))
def run(self):
th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400))
th2.start()
class Receiving():
def __init__(self, host, port):
self.host = host
self.port = port
def create_socket(self, host, port):
logging.debug('Starting socket')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((host, port))
#print ('socket ready')
time.sleep(5)
while True:
data, addr = sock.recvfrom(1500)
print('Prijata:' + data + addr)
def run(self):
th1 = threading.Thread(name = 'rec', target=self.create_socket('localhost', 8000))
th1.setDaemon(True)
th1.start()
if __name__ == '__main__':
#print ('running')
rec = Receiving('localhost', 8000)
send = Sending('username', 'localhost', 8001)
send.run()
rec.run()
Congrats on your introduction to Python! It looks like you're using Python 3, and in future questions it's helpful if you are explicit about which version you're using because there are minor but program-breaking incompatibilities in some code (including this code!).
I found a few errors in your program:
The most major issue - as Trevor Barnwell says, you're not calling threading.Thread quite correctly. The target= argument needs to be a callable object (i.e. function), but in this case it should just be a reference to the function. If you add brackets to the function, self.create_socket(host, port) as you have above, it actually runs the function immediately. As Trevor explained, your Sending.send() method was called early, but additionally there was a similar bug in Receiving. Because Receiving.create_socket() creates an infinite loop, it never returns program execution. While the console output looks correct to the user, the actual program execution has never made it to running the listener in a separate thread.
bytearray.extend() takes an iterable of ints, what you're passing right now is a tuple of byte objects.
In Sending.send() you call self.sock, but you never assign self.sock a value, so it fails.
Sending.run() only runs Sending.send() one time. After completing input for the user, it immediately exits, because the program has finished.
If you're looking for an in-depth, project based introduction to Python appropriate for an experienced programmer (including an exercise very similar to this question on basic sockets, and another on threading), I highly recommend you check out Wesley Chun's "Core Python Applications Programming". The most recent edition (3rd) has a lot of Python 2 code, but it's easily portable to Python 3 with some minor work on the reader's part.
I tried to modify your code as little as possible to get it working, here it is:
import socket
import threading
import logging
import time
class Sending():
def __init__(self, name, tHost, tPort, target):
self.name = name
self.host = tHost
self.port = tPort
self.target_port = target
self.sock = self.create_socket()
def create_socket(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((self.host, self.port))
return sock
def set_name(self, name):
self.name = name
def send_loop(self):
while True:
logging.debug('Starting send run')
message = input('Enter message: ')
data = bytearray()
data.extend(message.encode('utf-8'))
self.sock.sendto(bytearray(data), (self.host, self.target_port))
def run(self):
th2 = threading.Thread(name='send', target=self.send_loop)
th2.start()
class Receiving():
def __init__(self, host, port):
self.host = host
self.port = port
def create_socket(self):
logging.debug('Starting socket')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((self.host, self.port))
print ('socket ready')
time.sleep(5)
while True:
data, addr = sock.recvfrom(1500)
print('\nPrijata:' + data.decode('utf-8') + str(addr))
def run(self):
th1 = threading.Thread(name='rec', target=self.create_socket)
print("Made it here")
th1.daemon = True
th1.start()
return
if __name__ == '__main__':
print('running')
rec = Receiving('localhost', 8000)
send = Sending('username', 'localhost', 8001, 8000)
rec.run()
send.run()
The threads are not blocking each other. send is called before a thread is even created.
th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400))
This line makes a call to send at:
self.send('username', 'localhost', 8001, 1, 1400)
I think you meant to do this:
th2 = threading.Thread(
target=self.send
args=('username', 'localhost', 8001, 1, 1400))
That way a thread will start that calls send on the next line.
Two other things:
You will want to loop in your functions because the thread terminates once the function does.
I think you mean raw_input instead of input
I am tyring to subsribe to an event on a UPnP device (the WeMo motion sensor). I first send an HTTP subscribe request to the device, and the device should start sending me event notification on the designated address. That part is working fine (except that I am getting too many notifications; even when the status is not changing, but it is a different problem for a different thread)
If I run the keepListening Function on a separate python process, everything is working fine . However, when I run the function as a thread, it doesn't work;
import socket
import requests
from threading import Thread
def keepListening(): #running this function on a separate process works
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(600)
sock.bind(('192.168.10.231',1234))
sock.listen(5)
while 1:
notification = ''
try:
conn, addr = sock.accept()
conn.setblocking(1)
notification= conn.recv(1024)
conn.sendall(r'''HTTP/1.1 200 OK
Content-Type: text/plain
''')
except Exception as er:
print er
print notification
x = Thread(target=keepListening)
x.start()
message = {
'CALLBACK': '<http://192.168.10.231:1234>',
'NT': 'upnp:event',
'TIMEOUT': 'Second-600',
'HOST': '192.168.10.159:49153'}
k = requests.request('SUBSCRIBE','http://192.168.10.159:49153/upnp/event/basicevent1',headers=message)
print k
# keep doing other important works
Each event notification must be replied with a 200 OK reply, otherwise the device won't send further notification; a fact I learned the hard way. A doubt I have, which might be silly, is that, when running in a thread, as opposed to a separate process, the reply message doesn't get sent in timely manner, so the device doesn't send any more notifications.
It is worth mentioning that, even when I run the function in a Thread, I do get the initial notification after the subscription (Devices must mandatorily send an initial notification right after a subscription according to UPnP protocol), but I get no further notification (indicating that my 200 OK reply didn't get through properly; I do see it in wireshark though)
Any idea on what might be the difference in running the function in a thread (as opposed to a separate process) that makes it fail?
Thank you.
I would assume, what is happening is that you end up sending your subscribe request before thread becomes active and starts listening on the interface. So the device can not connect to the socket.
A few day ago I got a wemo motion sensor, switch and RaspberryPi, so I started tinkering.
The script subscribes to the „binaryState“-event of the wemo-device.
Every time the event occurs it prints out an „Alert“ (you can do other things there).
After 250 seconds it renews the subscription.
To adapt the script to your needs, you have to change the IPs:
localIp : your Computer
remoteIp: the ip of the wemo-sensor or switch
I’m new to python (started 3 days ago), so the script might need some revision, but it works.
import socket
import threading
import requests
host = ''
port = 1234
localIp = '<http://192.168.1.32:1234>' # local IP of your computer
remoteIp = '192.168.1.47:49153' # the ip of the wemo device
global uid # stores the uuid of the event
uid = ''
class client(threading.Thread):
def __init__(self, conn):
super(client, self).__init__()
self.conn = conn
self.data = ""
def run(self):
global uid
while True:
self.data = self.data + self.conn.recv(1024)
if self.data.endswith(u"\r\n"):
print self.data # data from the wemo device
uidPos = self.data.find("uuid")
if uidPos != -1: # data contains the uuid of the event
uid = self.data[uidPos+5:uidPos+41]
if "<BinaryState>1</BinaryState>" in self.data:
print "ALERT ------------------------------------------Alert"
# NOTIFICATION !
if "/e:propertyset" in self.data:
self.conn.sendall('HTTP/1.1 200 OK\r\nContent-Type:text/html\r\n\r\n')
return
self.data = ""
def send_msg(self,msg):
self.conn.send(msg)
def close(self):
self.conn.close()
class connectionThread(threading.Thread):
def __init__(self, host, port):
super(connectionThread, self).__init__()
try:
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((host,port))
self.s.listen(5)
except socket.error:
print 'Failed to create socket'
sys.exit()
self.clients = []
def run(self):
while True:
print uid
conn, address = self.s.accept()
c = client(conn)
c.start()
print '[+] Client connected: {0}'.format(address[0])
def main():
get_conns = connectionThread(host, port)
get_conns.start()
print get_conns.clients
while True:
try:
response = raw_input()
except KeyboardInterrupt:
sys.exit()
def setCalback():
global uid
threading.Timer(250.0, setCalback).start()
if uid == "": # no uuid set so we subscribe to the event
eventSubscribe()
else: # uuid is set, so we renew the subsciption
eventRefresh()
def eventSubscribe(): # subscribe to the wemo-event
message = {
'CALLBACK': localIp,
'NT': 'upnp:event',
'TIMEOUT': 'Second-300',
'HOST': remoteIp}
k = requests.request('SUBSCRIBE', "http://"+remoteIp+'/upnp/event/basicevent1',headers=message)
print k
def eventRefresh() # refresh the subscription with the known uuid
myuid = "uuid:"+uid
message = {
'SID': myuid,
'TIMEOUT': 'Second-300',
'HOST': remoteIp }
k = requests.request('SUBSCRIBE',"http://"+remoteIp+'/upnp/event/basicevent1',headers=message)
print k
if __name__ == '__main__':
threading.Timer(2.0, setCalback).start() # wait 2 sec. then subscribe to the service
main()
So I'm learning about socket programming and have wrote a nifty little chat server. The problem I am having is that my client cannot read and write at the same time. I'm not too sure how to set this up.
This is what I have so far, I want read() and write() to be running concurrently (It isn't so much about reading and writing at the same time - it's about being able to receive messages while input() hangs waiting for user input.):
import socket
import threading
class Client(threading.Thread):
def __init__(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(('127.0.0.1', 1234))
print('Client connected to server')
self.readThread = threading.Thread.__init__(self)
self.writeThread = threading.Thread.__init__(self)
def read(self):
data = self.socket.recv(1024)
if data:
print('Received:', data)
def write(self):
message = input()
self.socket.send(bytes(message, 'utf-8'))
client = Client()
while True:
#do both
You're really close. Try something like this:
import socket
import threading
class Client(threading.Thread):
def __init__(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(('127.0.0.1', 1234))
print('Client connected to server')
t = threading.Thread(target = self.read)
t.daemon = True # helpful if you want it to die automatically
t.start()
t2 = threading.thread(target = self.write)
t2.daemon = True
t2.start()
def read(self):
while True:
data = self.socket.recv(1024)
if data:
print('Received:', data)
def write(self):
while True:
message = input()
self.socket.send(bytes(message, 'utf-8'))
client = Client()
It's worth pointing out that if you're reading and writing from a single terminal this way your prompt could get a little out of hand. I imagine though that you're starting with print statements, but will eventually collect data into other containers in your app.