Multithreaded webserver in Python - python

An example from a video lecture. Background: the lecturer gave a simplest web server in python. He created a socket, binded it, made listening, accepted a connection, received data, and send it back to the client in uppercase. Then he said that there is a drawback: this web server is single-threaded. Then let's fork.
I can't understand the example well enough. But to start with, the program exits (sys.exit()). But I can't run it again:
socket.error: [Errno 98] Address already in use.
I try to find out which process is listening on port 8080: netstat --listen | grep 8080. Nothing.
Well, what is listening on 8080? And how to kill it?
Added later:
There is a feeling that if I wait for some time (say, 5-10 minutes), I can run the program again.
import os
import socket
import sys
server_socket = socket.socket()
server_socket.bind(('', 8080))
server_socket.listen(10)
print "Listening"
while True:
client_socket, remote_address = server_socket.accept()
print "PID: {}".format(os.getpid())
child_pid = os.fork()
print "child_pid {}".format(child_pid)
if child_pid == 0:
request = client_socket.recv(1024)
client_socket.send(request.upper())
print '(child {}): {}'.format(client_socket.getpeername(), request)
client_socket.close()
sys.exit()
else:
client_socket.close()
server_socket.close()

The correct netstat usage is:
netstat -tanp
because you need the -a option to display listening sockets. Add grep to locate your program quickly:
netstat -tanp| grep 8080

Related

How to connect a "client" socket on any network in the world to my "socket server"

I made a socket to see how it works.
Basically my intention for testing was to run commands in client computer cmd
First I made the server to receive a connection from my other script client
import socket
HOST = '192.168.100.xx' #my computer ipv4
PORT = 50000
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((HOST,PORT))
server.listen(5)
print('Server waiting connection...')
conn,addr = server.accept()
print('Connection established!')
print('Connected in addr: {}\n'.format(addr))
while True:
cmd = str(input('command>'))
conn.send(str.encode(cmd))
response = str(conn.recv(1024),"utf-8")
print(response)
if cmd == 'quit':
break
server.close()
Then I made the client:
import socket
import subprocess
import os
HOST = '192.168.100.xx' #ipv4 from my computer (server)
PORT = 50000
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((HOST,PORT))
print('Connecting to the server {}'.format(HOST))
while True:
command = client.recv(1024).decode()
print('Server command>'+command)
cmd = subprocess.Popen(args=command,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = (cmd.stdout.read() + cmd.stderr.read()).decode("utf-8", errors="ignore")
client.send(str.encode(str(output)+ str(os.getcwd()) +'$'))
Here's how I get my IPv4 address:
Initially when I tested it on a machine on my network this worked fine, but when I sent the client to a friend far away to run it, it didn't work.
I would like to know what I do to be able to use my socket server to connect with socket client in any corner of the world.
You are using a local ip which allows people connected only to your router connect.
So you need to use your public ip address. (Click Here to check your IP)
Open a port in your router. for example: 1234.
Dont know how? See this video.
Want to learn about it? See this video.
Once you do that, change the port in your code to the port you opened on the router page.
and then change the ip in the client code to your public ip.
Now your friend should be able to connect to your server.
(also you need to have static ip and not dynamic ip)

How to create Python API or network requests hidden (protected from hackers checking network traffic) on Local Network to manage Computers

I know that I can see inside of network traffic for example with WireShark. When i use GET on HTML I can see those stuff in URL, what should not be problem what I am doing. But I believe GET,POST and maybe REQUEST too, as I did not work with that one yet can bee seen on something like Wire Shark network analyzer.
I am making Python client, what i will put on computers in network to show their IP,Host Name and Users on PC. This client will be as gate to the computer for remote control. As our management does not want to spend money for windows server, or other management system we need to get something free to manage all computers.
I am also seeking advice how I could do it as you are more skilled then me here.
I found few ways.
With the client create SSH Gateway for receiving commands.
With Client enable the Powershell remote option, then just push scripts to all computers at once.
Use some way the API requests etc... I am not skilled in this one at all, but I believe this is the way how other similar programs works?
As this client would create big security risk, I am first seeking way what is best way to hide it from network. Probably I will need to come up with some Private and public Key system here as well.
What are yours suggestions please on this topic?
here is just very short code I am playing with to receive basic info as IP, Host name and all Users
the Flask website showing those values is just for test, It will not be there once it is deployed
Update
I took advice from MarulForFlask but I got a couple issues. First this i think can have only one connection at a time. And second if possible Can i get the output of console from the client PC on screen of Server PC?
I want this output only for testing, as I know if i do something like netstat or any other command with multiple clients it would filled up screen with too many text... Currently I am getting back text format as plaintext with \r \n ... and other text deviders.
I am now trying Multicast, but i am getting error for binding the multicast IP.
OSError: [WinError 10049] The requested address is not valid in its context
Master.py
import time
import socket
import sys
import os
valueExit = True
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = socket.gethostname()
BUFFER_SIZE = 1024
# Initialize the port
port = 8080
# Bind the socket with port and host
s.bind(('', port))
print("waiting for connections...")
# listening for conections
s.listen()
# accepting the incoming connections
conn, addr = s.accept()
print(addr, "is connected to server")
def send_query():
keepAllive, repeatIt = True, False
print("""To exit session write: EndSession
For help write: help
""")
while (keepAllive == True):
# commands for server use only
innerCommands = ["endsession", "help"]
# take command as input
command = input(str("Enter Command : "))
if command not in innerCommands:
conn.send(command.encode())
print("Command has been sent successfully.")
keepAllive = False
repeatIt = True
elif (command == "endsession"):
conn.send(command.encode())
valueExit = False
elif (command == "help"):
print("""To exit session write: EndSession""")
while (repeatIt == True):
# recieve the confrmation
data = conn.recv(BUFFER_SIZE)
if data:
print(f"command recieved and executed sucessfully.\n {data}")
keepAllive = True
repeatIt = False
else:
print("No reply from computer")
keepAllive = True
repeatIt = False
while valueExit == True:
send_query()
Slave.py
import time
import socket
import sys
import subprocess
import os
stayOn = True
def establishConnection():
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = "127.0.0.1"
# Initiaze the port
port = 8080
keepAlive = True
try:
# bind the socket with port and host
s.connect((host, port))
print("Connected to Server.")
while keepAlive == True:
# recieve the command from master program
command = s.recv(1024)
command = command.decode()
# match the command and execute it on slave system
if command == "endsession":
print("Program Ended")
keepAlive = False
elif command != "":
# print("Command is :", command)
#s.send("Command recieved".encode())
proc = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
s.send(f"{out}".encode())
print("program output:", out)
except Exception as err:
print(f"Error: {err}")
s.send(f"Error: {err}".encode())
while stayOn == True:
establishConnection()
see:
https://www.pythonforthelab.com/blog/how-to-control-a-device-through-the-network/
There uses a flask webserver.
otherwise, create a master.py file and paste this code:
import time
import socket
import sys
import os
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = socket.gethostname()
# Initialize the port
port = 8080
# Bind the socket with port and host
s.bind(('', port))
print("waiting for connections...")
# listening for conections
s.listen()
# accepting the incoming connections
conn, addr = s.accept()
print(addr, "is connected to server")
# take command as input
command = input(str("Enter Command :"))
conn.send(command.encode())
print("Command has been sent successfully.")
# recieve the confrmation
data = conn.recv(1024)
if data:
print("command recieved and executed sucessfully.")
open a slave.py and paste this code:
import time
import socket
import sys
import os
# Initialize s to socket
s = socket.socket()
# Initialize the host
host = "127.0.0.1"
# Initiaze the port
port = 8080
# bind the socket with port and host
s.connect((host, port))
print("Connected to Server.")
# recieve the command from master program
command = s.recv(1024)
command = command.decode()
# match the command and execute it on slave system
if command == "open":
print("Command is :", command)
s.send("Command recieved".encode())
# you can give batch file as input here
os.system('ls')
open slave.py in client, master.py in server
https://www.geeksforgeeks.org/how-to-control-pc-from-anywhere-using-python/

Send a string between python programs

I want to send some simple information, like an int or a string, between two Python programs. I thought of doing it by having the programs read and write from a single-line file. But that doesn't seem to work, since one file seems to block the file. Especially since I want to check for updates every 1/12 of a second or so.
If it did work, my idea use case would be for one program to send a message with
with open('input.py','w') as file:
file.write('hello')
and receive it with
with open('input.py','r') as file:
print(file.read())
I've been looking into how to do it with sockets, but every 'simple' tutorial seems to be targeted some much more complex use case. So how do I do what I need to do in a way that'll actually work?
The best route to go is to use the socket library. This creates a client-server connection, where you can send strings between programs from there.
server.py:
import socket
s = socket.socket()
print "Socket successfully created"
port = 12345 # Reserve a port on your computer...in our case it is 12345, but it can be anything
s.bind(('', port))
print "Socket binded to %s" %(port)
s.listen(5) # Put the socket into listening mode
print "Socket is listening"
while True:
c, addr = s.accept() # Establish connection with client
print 'Got connection from', addr
c.send('Thank you for connecting') # Send a message to the client
c.close()
client.py:
import socket
s = socket.socket()
port = 12345 # Define the port on which you want to connect
s.connect(('127.0.0.1', port)) # Connect to the server on local computer
print s.recv(1024) # Receive data from the server
s.close()
From the terminal/shell:
# start the server:
$ python server.py
Socket successfully created
Socket binded to 12345
Socket is listening
Got connection from ('127.0.0.1', 52617)
# start the client:
$ python client.py
Thank you for connecting
As you can see, the client was able to receive the string "Thank you for connecting" by the server, thanks to the send() and recv() methods from the socket library.

closing open socket in python

Im wondering is there any way to find out the socket that is open and then to close it?
For instance,I have a script "SendInfo.py" which opens a socket and sends some info over TCP.
If I call this script to run it e.g. "python SendInfo.py" , it will open a new socket.
If I run this script again using "python SendInfo.py", which will send some more up to date information, I would like to cancel the previous TCP transaction and start a new one - e.g. by closing the previous socket.
How do I get access to the open socket at the beginning of my script in order to close it? Ive tried looking into threads, but Im similarly confused about which threads are open and how to close open threads etc.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(2)
s.connect((self.__host, PORT))
I'm not sure if this is what you are after but here is a method of ensuring that the script is only running once and killing an existing running script.
You may find something useful in it. (This is for Linux)
#!/usr/bin/python
# running.py
# execute by making the script executable
# put it somewhere on $PATH and execute via running.py
# or execute via ./running.py
import os, sys, time , signal, socket
running_pid = os.popen('ps --no-headers -C running.py').read(5)
try:
running_pid = int(running_pid)
except:
running_pid = 0
current_pid = int(os.getpid())
if running_pid != 0:
if running_pid != current_pid:
print "Already running as process", running_pid
print "Killing process", running_pid
os.kill(int(running_pid), signal.SIGKILL)
# sys.exit()
# Create a listening socket for external requests
tcp_port = 5005
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print "Error on Socket 5005"
# force re-use of the socket if it is in time-out mode after being closed
# other wise we can get bind errors after closing and attempting to start again
# within a minute or so
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sock.settimeout(0.10)
sock.bind(("localhost", tcp_port))
except IOError as msg:
print "Error on Socket Bind "+str(tcp_port)+", running.py is probably already running"
pass
try:
sock.listen((1))
except:
print "Error on Socket listen"
time.sleep(60)
sock.close()

Connect to Socket on localhost

I have trouble connecting to my own socket on localhost.
s.connect(('127.0.0.1', 4458)) (or "localhost") will just take forever,
and eventually timeout with TimeoutError: [Errno 110] Connection timed out
It should open port 4458, another script will then send some chars to it. Both scripts are supposed to run on the same Raspberry Pi, while 'server' one will execute with sudo (to access the GPIOs) and one without, being a chat bot.
I have no trouble running the server on the Pi (with python 3.4.1) and the client on my Laptop (mac, python 3.4.2).
Also it does work in reverse direction, server script on the laptop and client on the Raspberry.
As final test, it works with both, the server and the client on the said macbook.
Just server + client on the Pi does not work.
The program freezes
My shortened code if it helps:
# $ sudo python3 server.py
__author__ = 'luckydonald'
import socket # server
import time # wait for retry
import threading
class Server(threading.Thread):
port = 4458;
QUIT = False
def run(self):
s = socket.socket()
failed = True
print ("Starting Server on Port %d" % (self.port))
while failed:
try:
s.bind(("", self.port))
except Exception as err:
print(err)
print("Port assignment Failed. Retring in 1 second.")
time.sleep(1)
else:
failed = False
print("Success.")
while not self.QUIT:
print("Listening!")
conn, addr = s.accept() # freezes here
print("Got something: %s , %s" %(str(conn), str(addr)))
while not self.QUIT:
result = conn.recv(1)
print("Got result: " + str(result))
server = Server();
server.daemon = True
server.run();
# server.start();
And for the client:
# python3 cilent.py
s = socket.socket()
print("connecting...")
s.connect(("localhost",4458)) # also tried "172.0.0.1" # freezes here
print("connected!")
s.sendall("+".encode("utf-8"))
s.sendall("-".encode("utf-8"))
s.close()
It will result in this:
What I didn't expected was that localhost/127.0.0.1 did not work.
100% package loss
I had a malformatted entry in my hosts file.
You should check for below items
there is an installed internet information services
iis is running
firewall is grants required ports for running the python.exe

Categories