Python Persistent HTTP web proxy - python

My client initially communicates using persistent HTTP with my own server. I am now trying to insert a web proxy in between them, so ideally the proxy will maintain 2 seperate persistent connections, one with the client and one with the server. How can I create a python web proxy that does that? I've only been able to create a non-persistent one so far, how would I expand it to do persistent connections?
Code so far:
def main():
# host and port info.
host = '' # blank for localhost
port = 80
try:
# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# associate the socket to host and port
s.bind((host, port))
# listenning
s.listen(BACKLOG)
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket:", message
sys.exit(1)
# get the connection from client
while 1:
print "Proxy running..."
conn, client_addr_port = s.accept()
# create a thread to handle request
thread.start_new_thread(proxy_thread, (conn, client_addr_port))
s.close()
def proxy_thread(conn, client_addr_port):
print "received something...creating new thread"
global threadcount
client_addr = client_addr_port[0]
client_port = client_addr_port[1]
# Check if this is an new video flow (assumption now is that 1 client has 1 video flow, and the video does not terminate)
if client_addr not in client_vid_flows:
print "New client detected", client_addr
client_vid_flows[client_addr] = 0 # Expand to save video rate
# ctrl_msg_timer(client_addr) # Start timer that sends a ctrl_msg to the switch at a certain frequency
with lock:
threadcount = threadcount + 1
print "Thread number:", threadcount
# get the request from browser
request_text = conn.recv(MAX_DATA_RECV)
request = HTTPRequest(request_text)
if not request:
sys.exit(1)
if request.error_code:
sys.exit(1)
host = request.headers['host']
port_pos = host.find(":") # find the port pos (if any)
if (port_pos==-1): # default port
webserver = host
port = 80
else: # specific port
webserver = host.split(":")[0]
port = host.split(":")[1]
print "Connect to: %s:%i" % (webserver, port)
try:
# create a socket to connect to the web server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((webserver, port))
s.send(request_text) # send request to webserver
while 1:
# receive data from web server
data = s.recv(MAX_DATA_RECV)
print data
if (len(data) > 0):
# send to browser
conn.send(data)
print 'more to send, len(data)={}'.format(len(data))
else:
print 'end of send'
# s.close()
# conn.close()
except socket.error, (value, message):
if s:
s.close()
if conn:
conn.close()
print "Runtime Error:", message
sys.exit(1)
print "--------------------------------"
#********** END PROXY_THREAD ***********
if __name__ == '__main__':
main()
From wireshark, I see that a request packet is being sent to the proxy. However, the proxy is not picking this up.

Related

TCP Connection through IP Addresses & Port in Python

We're trying to establish a TCP connection in Python 3.8, where we want each machine to become a client and a server at the same time, so that each machine can send and receive messages. With this code, we can send and receive data (sometimes), but we have noticed that each machine can send messages to the first ip address in the IPs list, but the rest are neglected.
Perhaps there's a better way than this to establish a TCP Connection, so we can send data to each other?
All three sections (Server, Client & Sharing Distribution) of codes are attached to a python program that each machine is running.
Start Distribution:
Here server socket is initiated, and we start threads for each ip-address we want to connect to.
def start_distributed_sharing(self):
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serv.bind(('0.0.0.0', 44445))
self.serv.listen(5)
MAX_CONNECTION = 5
IPs = ['{ip-address}', '{ip-address}', '{ip-address}', ]
client_threads = []
for ip in IPs:
client_threads.append(threading.Thread(target=self.client, args=(ip,)))
for i in range(0, len(client_threads)):
client_threads[i].start()
print("Clients is running")
while True:
conn, addr = self.serv.accept()
server_thread = threading.Thread(target=self.server, args=(conn, addr,))
server_thread.start()
print("New connection to server created!")
Server:
Each Machine starts their own server, and waits for a client to connect
def server(self, conn, addr):
while True:
data = ''
try:
data = conn.recv(4096)
except Exception:
print("Server: Lost a connection... Retrying...")
time.sleep(5)
break
if not data: break
try:
data = json.loads(data.decode('utf-8'))
print(data)
except Exception:
print("Server: Could not decode message: ", data)
conn.close()
print('Server: client disconnected')
Client:
Here the client attempts to connect to the server with the given ip-addresses
def client(self, ip):
# print(ip)
self.cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
connected = False
while not connected:
try:
print("Client: Connecting to, ", ip)
self.cli.connect((ip, 44445))
connected = True
except Exception:
print('Client: Could not connect to: ', ip, '. Retrying...')
time.sleep(5)
while True:
time.sleep(2)
try:
print("Client: Sending a msg to, ", ip)
self.cli.send(json.dumps({"id": "{PC1}", "height": self.nodes[self.current_leader].node_stats.lastBlockHeight, "latency": self.nodes[self.current_leader].avgLatencyRecords}).encode('utf-8'))
except Exception:
print("Client: Could not send more data to, ", ip)
break
if I understood correctly you want only one server for each (machine / program)? In this case, I think you need a unique port for each server. Or if you want each client to behave like a client / server to communicate with the main server, you can use your client's recv method.
Exemple 1 (send message to server and wait response):
def client(self, ip):
self.cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
connected = False
while not connected:
try:
print("Client: Connecting to, ", ip)
self.cli.connect((ip, 44445))
connected = True
except Exception:
print('Client: Could not connect to: ', ip, '. Retrying...')
time.sleep(5)
while True:
time.sleep(2)
try:
print("Client: Sending a msg to, ", ip)
self.cli.send(json.dumps({"id": "{PC1}", "height": self.nodes[self.current_leader].node_stats.lastBlockHeight, "latency": self.nodes[self.current_leader].avgLatencyRecords}).encode('utf-8'))
except Exception:
print("Client: Could not send more data to, ", ip)
break
# Waiting for server response
response = self.cli.recv(1024)
Now if you want a server message event, you can create a message handler like this (it is not very clean code it is for the example):
def on_message(self, msg):
print(msg)
def message_handle(self):
while True:
# Waiting for server message
msg = self.cli.recv(1024)
# check is message if valid
self.on_message(msg)
def client(self, ip):
# print(ip)
self.cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
connected = False
while not connected:
try:
print("Client: Connecting to, ", ip)
self.cli.connect((ip, 44445))
connected = True
except Exception:
print('Client: Could not connect to: ', ip, '. Retrying...')
time.sleep(5)
# Connection established start message handler
handler = threading.Thread(target=self.message_handle))
handler.start()
while True:
time.sleep(2)
try:
print("Client: Sending a msg to, ", ip)
self.cli.send(json.dumps({"id": "{PC1}", "height": self.nodes[self.current_leader].node_stats.lastBlockHeight, "latency": self.nodes[self.current_leader].avgLatencyRecords}).encode('utf-8'))
except Exception:
print("Client: Could not send more data to, ", ip)
break
In this example, you only had one server and clients on each machine. Then you have to manage the redirection of messages to target clients at the server level (identify the client sending the message and the target clients to address the messages to the right clients).

check time between messages sent from client to server application

I want my server to send the string "con-res 0xFE" to reset the server if it has been more than 4 seconds since a new message was sent by the client.
I have tried to puzzle around with time.time() but in the end I can't figure out how to register a time for each message it self.
Client:
import socket
# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 12000)
number_of_packages = 0;
try:
while True:
message = input("Write something: ")
# Send data
sent = sock.sendto(message.encode(), server_address)
number_of_packages +=1
if (number_of_packages > 25):
print("Too many packages - closing socket")
socket.close()
# Receive response
data, server = sock.recvfrom(4096)
print('client received: ', data.decode())
if data.decode()=="con-res 0xFE":
print("conn reset!")
sent = sock.sendto("con-res 0xFFDDDDD".encode(), server_address)
finally:
sock.close()
My server:
# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind the socket to the port
server_address = ('localhost', 12000)
sock.bind(server_address)
count_message = 0
while True:
data, address = sock.recvfrom(4096)
#check 4 seconds since last message
if data:
start_time = time.time()
sent = sock.sendto("ok".encode(), address)
The above code incidents might be wrong as I had difficulties make sure it looked as code here on Stackoverflow. However the above code is working as it should.

problem with socket programming on my host

i wanted to use a website to send some commands to a client app but in my host i can just access to ports 80 and 443 is it possible that i make socket programming with these ports?
i have tried my code on some ports like 8889 and but these are not available on my host
def send_to_client(key)://///the function on website that sends data to client
HOST = '10.42.0.158' # The server's hostname or IP address
PORT = 8889 # The port used by the server
connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection.connect((HOST, PORT))
print("problem with socket")
# old = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
/////if key is ok send it to client app
connection.sendall(key)
return key + " sent succesfully"
else:
return "not proper input"
# key = sys.stdin.read(1)
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old)
def recv_data()://///the function on client app that receive data from website
global data
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print ('Connected with ' + addr[0] + ':' + str(addr[1]))
while True:
d = conn.recv(1024).strip().decode('utf-8')
data = d
break
i want to know that is it possible that use port 80 to do this socket programming app

Username/handle system using Python - TCP/IP chat client

Here is my server code.
# chat_server.py
import sys, socket, select
HOST = ''
SOCKET_LIST = []
RECV_BUFFER = 4096
PORT = 9009
def chat_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# add server socket object to the list of readable connections
SOCKET_LIST.append(server_socket)
print "Chat server started on port " + str(PORT)
while 1:
# get the list sockets which are ready to be read through select
# 4th arg, time_out = 0 : poll and never block
ready_to_read,ready_to_write,in_error = select.select(SOCKET_LIST,[],[],0)
for sock in ready_to_read:
# a new connection request recieved
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
print "Client (%s, %s) connected" % addr
broadcast(server_socket, sockfd, "[%s:%s] entered our chatting room\n" % addr)
# a message from a client, not a new connection
else:
# process data recieved from client,
try:
# receiving data from the socket.
data = sock.recv(RECV_BUFFER)
if data:
# there is something in the socket
broadcast(server_socket, sock, "\r" + '[' + str(sock.getpeername()) + '] ' + data)
else:
# remove the socket that's broken
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
# at this stage, no data means probably the connection has been broken
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
# exception
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
server_socket.close()
# broadcast chat messages to all connected clients
def broadcast (server_socket, sock, message):
for socket in SOCKET_LIST:
# send the message only to peer
if socket != server_socket and socket != sock :
try :
socket.send(message)
except :
# broken socket connection
socket.close()
# broken socket, remove it
if socket in SOCKET_LIST:
SOCKET_LIST.remove(socket)
if __name__ == "__main__":
sys.exit(chat_server())
Here is my client code.
# chat_client.py
import sys, socket, select
def chat_client():
if(len(sys.argv) < 3) :
print 'Usage : python chat_client.py hostname port'
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
# connect to remote host
try :
s.connect((host, port))
except :
print 'Unable to connect'
sys.exit()
# TEST
person = raw_input ('Please enter your username: ')
print 'Connected to remote host. You can start sending messages.'
sys.stdout.write( person + '[Me]: ' ); sys.stdout.flush()
while 1:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])
for sock in read_sockets:
if sock == s:
# incoming message from remote server, s
data = sock.recv(4096)
if not data :
print '\nDisconnected from chat server'
sys.exit()
else :
#print data
sys.stdout.write(data)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
else :
# user entered a message
msg = sys.stdin.readline()
s.send(msg)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
if __name__ == "__main__":
sys.exit(chat_client())
I'm currently trying to work on adding sort of a "handle" system into the chat client. If you were to run this code, you'll notice that the handle you choose is only displayed on your client, and not anybody else's. I've done hours of research already, and I can't for the life of me figure out how to have a client's chosen handle displayed onto other clients.
I'm still relatively new to Python, and especially new to TCP/IP programming. Any help, advice, and constructive criticism will be welcomed. Thanks in advance!
You can do it on the server or the client side
Server side
To implement it server side, you need to maintain some kind of mapping in the server between client sockets and handles, so that when you broadcast a message from a socket, you can retrieve its handle and prepend it to the message before sending.
In order to know the handle of the clients, they can send it to the server as the first message when they connect. The server will interpret this first message as the handle, and store it mapping it to the socket from what it has been received.
The advantage of this approach is that the server can validate the handle before it accepts it from the clients, and if it is already in use, reject the handle or abort the connection. Also, the clients cannot fake their handle later in the conversation, as it is the server that sends them.
Client side
This is the easiest implementation, as you only need to modify the client and prepend the handle before sending each message.
# user entered a message
msg = sys.stdin.readline()
s.send(person + ": " + msg)
sys.stdout.write( person + '[Me]: '); sys.stdout.flush()
The drawbacks of this approach are that a malicious client can fake the handle to pretend to be another person, and that two clients can have the same handle at the same time, making them indistinguishable from each other.

Python socket: Bad File Descriptor for simple client connection script

My script is very simple.
1.) Server listens for an HTTP connection
2.) Client establishes connection
3.) Server prints our the client's HTTP request data
When a client connects to the server and makes a browser request it triggers the Socket error "Bad File Descriptor".
I'm not sure why it does this. Can anyone help me out?
import socket
host = ''
port = 1000
def proxy(connection,client):
request = connection.recv(MAX_DATA_RECV)
print request
connection.close()
def main():
try:
# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# associate the socket to host and port
s.bind((host, port))
# listenning
s.listen(BACKLOG)
print("Listening for connections")
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket:", message
# get the connection from client
while 1:
try:
conn, client_addr = s.accept()
print("Received connection from " + str(client_addr))
proxy(conn,client_addr)
#thread.start_new_thread(proxy, (conn,client_addr))
if s:
s.close()
except socket.error, (value,message):
print value
print message
sys.exit(1)
main()
You are closing the server socket after first client. Don't do this.
while True:
try:
conn, client_addr = s.accept()
print("Received connection from " + str(client_addr))
proxy(conn,client_addr)
except socket.error, (value,message):
print value
print message

Categories

Resources