For a school project I need to open a proxy server in python. My proxy server works and shows the page on the browser but the problem is that it doesn't close connections after page shown and no more requests sent. The problem happens specifically after Connect Requests that start a proxy tunnel so I don't know when should I close the connection between the client and the server.
When and how should I close the connection between them?
def get_data(sock):
data = b''
data_add = b'test'
try:
while len(data_add) != 0:
# receive data from web server
data_add = sock.recv(4096)
data += data_add
except Exception as e:
print("2:" + str(e) + " ")
return data
def handle_connect_command(client_socket, my_socket):
request = b'test'
try:
send_data(client_socket, b'HTTP/1.1 200 OK\r\n\r\n')
while True:
request = get_data(client_socket)
send_data(my_socket, request)
response = get_data(my_socket)
send_data(client_socket, response)
except Exception as e:
print("5:" + str(e))
print("Connection lost")
client_socket.close()
my_socket.close()
def threaded(client_socket):
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
request = b'Test'
try:
while len(request) > 0:
# data received from client
request = get_data(client_socket)
web_server, port, command = analyze_request(request)
print(web_server + ' ' + str(port))
my_socket = connect_to_server(web_server, port)
if command.lower() == "connect":
handle_connect_command(client_socket, my_socket)
break
else:
send_data(my_socket, request)
response = get_data(my_socket)
my_socket.close()
send_data(client_socket, response)
except Exception as e:
print("6:" + str(e))
# connection closed
client_socket.close()
my_socket.close()
Assuming you're using sock/sockets you can simply run:
server.quit()
or
session.close()
if you're using requests.
after creating a server object.
The matter of WHEN to close the connection is something we would need to see your code for.
logically you would close the connection when no more interaction needs to take place
If you are using the Requests library (and you should) you can do this.
with requests.Session() as session:
session.get('target_url')
This will close the connection automatically when everything in the with condition completes.
Related
I'm trying to write a simple 'https over http tunnel' server in python.
Every other thing works out fine except the connection between the client and the server persist and ends up blocking( forever ).
I'm pretty sure they carry out the SLL handshake because they both send and receive a couple of times before it hangs.
here's the server code:
import socket
import threading
class SocketWrapper:
def __init__(self,sock = None):
if sock is None:
self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
else:
self.socket = sock
def connect(self,host,port):
try:
self.socket.connect((host,int(port)))
return True
except socket.error:
return False
def close(self):
# close the socket connection
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
def send(self,data):
bytes_sent = 0
msg_len = len(data)
while bytes_sent < msg_len:
sent = self.socket.send(data[bytes_sent:])
bytes_sent += sent
def receive(self):
chunks = []
while True:
try:
self.socket.settimeout(0.5)
chunk = self.socket.recv(4096)
chunks.append(chunk)
except socket.error:
self.socket.settimeout(0)
break;
return b''.join(chunks)
class HttpTunnel:
def __init__(self,host='localhost',port=3000):
# create the server socket,bind and listen
self.host,self.port = host,port
self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.socket.bind((self.host,self.port))
self.socket.listen(3)
print("listening on port",self.port)
self.running = True
def handleClientRequest(self,connection,address):
print("Connected to",address)
clientSocket = SocketWrapper(connection)
meta = clientSocket.receive().decode().split('\r\n')[0]
# getting method,uri,version from 'CONNECT host:port HTTP/1.1'
method,uri,version = meta.split(' ')
host,port = uri.split(':')
serverSocket = SocketWrapper()
# if connection to the remote server is created successfuly
if(serverSocket.connect(host,port)):
print("Connected to remote server")
# send connection success message to the client
clientSocket.send(b'HTTP/1.1 200 OK\r\n\r\n');
while True:
try:
clientResponse = clientSocket.receive()
serverSocket.send(clientResponse)
print("Sent client - server")
serverResponse = serverSocket.receive()
clientSocket.send(serverResponse)
print("Sent server - client")
except socket.error:
break;
else:
# send someking of error. In this case 404
serverSocket.send(b'HTTP/1.1 404 Not Found\r\n\r\n')
# close the connection
clientSocket.close()
serverSocket.close()
def mainloop(self):
while self.running:
# accept client connection
connection,address = self.socket.accept()
self.handleClientRequest(connection,address)
proxy = HttpTunnel()
proxy.mainloop()
the client code:
import urllib
import urllib.request as request
proxy = request.ProxyHandler({
'https':'https://127.0.0.1:3000'
})
opener = request.build_opener(proxy)
request.install_opener(opener)
try:
resp = request.urlopen('https://google.com')
print(resp.read())
except Exception as e:
print(e)
the client did not get the response from the server and therefore prints nothing.
here's the server output:
listening on port 3000
Connected to ('127.0.0.1', 54888)
Connected to remote server
Sent client - server
Sent server - client
Sent client - server
Sent server - client
Sent client - server
There are several problems here:
The main problem is that you don't handle the case when recv returns 0 since the socket gets closed. Instead you run into an endless loop where no data get read and no data get send. Some simple print statements which actually show how much data are read would have helped to track this problem down.
Apart from that the idea of polling each file handle after each other using settimeout is a bad approach. Instead check the file handles in parallel and then read from the one which has data - see select.
And finally you are assuming that socket.send will send all data given. This is not the case, it might send less. Check the return code or just use socket.sendall
I am running a simple form input on my localhost:port using socket programming.
Currently, I have a form running on my chrome, just a text box on localhost:2333, I am able to see the text box input on my wireshark like this
The input message I typed is testesest.
After which, I put the <form action="http://localhost:2333"> such that the entered form data can flow back to my localhost:port. However, my 2nd r= recv(1024)is not receiving anything.
import socket
import sys
import os
Addr = ''
PORT = 2333
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((Addr, PORT))
s.listen()
The above is the standard part.
while(1):
try:
print("waiting for connection")
conn, address = s.accept()
print("New client connected from IP address {} and port number {}".format(*address))
received = conn.recv(1024)
#print("Request received")
#This is what i am hosting
#A webpage with a form
conn.send(b'\r\n')
#This is the webpage content
#The code will stuck here at recv
print("Waiting for form input from client")
r = conn.recv(1024)
print(r.decode())
print("Form input received")
print("HTTP response sent")
except KeyboardInterrupt:
conn.close()
s.close()
conn.close()
s.close()
break
Can I get some help please?
Input data sent via GET is attached to the URI (/?work=<data>), which is sent as a new request:
import socket
import sys
import os
Addr = ''
PORT = 2333
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((Addr, PORT))
s.listen()
while (1):
try:
print("waiting for connection")
conn, address = s.accept()
print(
"New client connected from IP address {} and port number {}".format(
*address
)
)
request = conn.recv(1024)
print("Request received")
method, uri, _ = request.decode().split(' ', 2)
print(method, uri)
#This is what i am hosting
#A webpage with a form
response = ""
conn.send(b'HTTP/1.1 200 OK\r\n')
conn.send(b'Content-Type: text/html\r\n')
conn.send(b'Host: localhost:2333\n')
conn.send(b'\r\n')
if uri == '/':
response = """<html>
<body><form action="http://localhost:2333/" method="GET">
<input type="text" name="work"></form></body>
</html>"""
elif uri.startswith('/?work'):
response = f"<html><body><h2>recevied: {uri[uri.find('/?work=')+7:]}</h2></body></html>"
conn.send(response.encode())
conn.send(b"\r\n")
print("Form input received")
#print("HTTP response sent")
except KeyboardInterrupt:
conn.close()
s.close()
#conn.close()
#s.close()
#break
Out:
waiting for connection
New client connected from IP address 127.0.0.1 and port number 55941
Request received
GET /?work=TestInput
<html><body><h2>recevied: TestInput</h2></body></html>
Form input received
waiting for connection
...
Note:
You might want to have a look at the protocol specs and/or use any existing library to get rid of this low level stuff.
Whenever we submit any form, browser makes new http request instead of using the existing connection, so you need to handle it in new http request/connection.
Another thing is, r = conn.recv(1024) is not letting the current connection close, that's why pressing enter in textfield is also not working.
This is my python code:
class SimpleWebServer():
def __init__(self, port):
threading.Thread.__init__(self)
self.port = port
self.BUFFER_SIZE = 8192
#Create a server socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#YOUR CODE
try:
#Bind to a port
#YOUR CODE; 1 line
self.server.bind(('localhost', self.port))
except socket.error:
print('Bind failed %s' % (socket.error))
sys.exit()
#Listen to the server socket
#YOUR CODE; 1 line
self.server.listen(5)
def run_thread(self, conn, addr):
# connection timeout after 60-second inactivity
conn.settimeout(60.0)
print('Client connected with ' + addr[0] + ':' + str(addr[1]))
while True:
try:
# Receives the request message from the client
message = self.server.recv(1024)
# .decode("utf-8") #YOUR CODE
if not message: break
# Extract the path of the requested object from the message
# The path is the second part of HTTP header, identified by [1]
filename = message.split()[1].decode()
print('Client request ' + filename)
# Extract the file extention to determine file type
filename_extension = os.path.splitext(filename)[1]
# Open the local file f specified in filename for reading
# Because the extracted path of the HTTP request includes
# a character '\', we read the path from the second character
f = open(filename)#YOUR CODE
# Store the entire content of the requested file in a temporary buffer
msg = f #YOUR CODE
# Send the HTTP response headers to the connection socket
# 1. HTTP version and status code
# YOUR CODE 1-line
#conn.send_response(200, addr)
conn.sendall(bytearray("HTTP/1.1 200 OK"))
# 2. Keep-Alive field
# YOUR CODE 1-line
#conn.send_head("Timeout = 5", "Max - 30", addr)
conn.sendall(bytearray("Timeout = 5", "Max - 30"))
# 3. Content length field
# YOUR CODE 1 - 3 lines
#conn.send_header("Content-length", len(msg), addr)
conn.sendall(bytearray("Content-length", len(msg)))
# 4. Content type field (based on the file type)
# YOUR CODE
#conn.send_header("Content-type", "text/html", addr)
#conn.end_headers()
conn.sendall(bytearray("Content-type", "text/html"))
# Send the HTTP response body
for i in range(0, len(msg), self.BUFFER_SIZE):
end = min(i + self.BUFFER_SIZE, len(msg))
conn.send(msg[i: end])
# Exception handling
except FileNotFoundError:
# Send HTTP response message for file not found
# YOUR CODE 1 - 3 lines
self.send_response(404)
except socket.timeout:
#Socket timeout
print("Conn socket timeout!")
break
except socket.error as e:
#Other socket exceptions
print("Socket error: %s" % e)
break
conn.close() # Close socket
def run(self):
print('Waiting for connections on port %s' % (self.port))
while True:
#Accept a new connection
try:
#Waiting for connection request
(conn, addr) = self.server.accept()
#Start a new thread to handle HTTP request/response
threading.Thread(target=self.run_thread, args=(conn, addr)).start()
except:
break
# Close the server socket
self.exit()
def exit(self):
"""Close server socket"""
self.server.close()
I call the class here:
if __name__ == '__main__':
parser = optparse.OptionParser(usage="%prog ServerPort")
options, args = parser.parse_args()
if len(args) < 1:
parser.error("No ServerPort")
else:
if validate_port(args[0]):
server_port = int(args[0])
else:
parser.error("ServerPort invalid!")
#Create and start the server
server = SimpleWebServer(server_port)
server.run()
I call the script via powershell and I get this error:
Client connected with 127.0.0.1:2654
Socket error: [WinError 10057] A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
I'm running this command in my browser to try and access this socket:
http://localhost:8888/index.html
I have no clue what I should be doing to fix this. There is a lot of documentation for python socket programming and I've tried many of the different methods but nothing has worked so far.
I am new to Python 2.7. I am writing a program where I need to check the availability of internet for my Wifi (sometimes the internet disconnects) before I proceed to send the data to the database using the Internet. The send data to database will be skipped if there is no internet connection. How can I do that. Is this the correct way that I doing this?
import urllib
#Perhaps check internet availability first
try:
import httplib
except:
import http.client as httplib
def have_internet():
conn = httplib.HTTPConnection("www.google.com", timeout=5)
try:
conn.request("HEAD", "/")
conn.close()
return True
except:
conn.close()
return False
#send data to database
data = {'date':date_mmddyyyy,'time':time_hhmmss,'airtemperature':temperature_c,'humidity':humidity_c, 'watertemperature':watertemp_c, 'phsolution':pHvalue_c, 'waterlevel':distance_c, 'CO2 concentration':CO2_c, 'TDS value':tds_c}
result = firebase.put('Region 1', 'Parameter Reading', {'date':date_mmddyyyy,'time':time_hhmmss,'airtemperature':temperature_c,'humidity':humidity_c, 'watertemperature':watertemp_c, 'phsolution':pHvalue_c, 'waterlevel':distance_c, 'CO2 concentration':CO2_c, 'TDS value':tds_c})
result2 = requests.post(firebase_url + '/' + reading_location + '/History/Parameter Reading.json', data=json.dumps(data))
print 'All parameter records are inserted.\nResult Code = ' + str(result2.status_code) + ',' + result2.text
I've used the requests module for this.
In the event of a network problem (e.g. DNS failure, refused connection, etc), Requests will raise a ConnectionError exception.
So you could do the following:
import requests
def is_connected():
try:
r = requests.get("http://google.com", timeout=5)
return True
except requests.exceptions.ConnectionError:
return False
Note that it may raise other exceptions, but this should be enough to start.
As suggested by #FranciscoCouzo, you can just try the connect and see what happens. But suppose you want a smaller sanity check before even delving into the database portion of your code. If you know the port number of your database server (1433 for instance) you can try a connect and then reset that connection. You still have to deal with loosing your wifi connection as you work, but this is a light weight way to know its okay to start.
import socket
import struct
def is_alive(host, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(5)
s.connect((host, port))
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
struct.pack("ii", 1, 0))
s.close()
except OSError:
return False
finally:
s.close()
return True
print(is_alive("example.com", 1344))
I have a program that launches a TCP client as well as a server, and I can send messages and files from client to the server (they are all transferred in this direction). The server is expected to be always listening, and respond each upcoming message. But I found after I sent several messages, the server never responds again, unless I relaunch connect button on GUI.
here we have in the server,
# establish connection
def conn(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((self.ip, self.port))
self.s.listen(1)
print 'server ready.'
self.conn, self.addr = self.s.accept()
print 'Connected by', str(self.addr), '\n'
def recv(self):
flag = self.conn.recv(BUFFER_SIZE)
data = self.conn.recv(BUFFER_SIZE)
# this is a message
if flag=='1':
msg = "other >> %s" % data
self.conn.send("success")
print msg
return
# there will be a file
elif flag=='0':
filename = data
with open('new_'+filename, 'wb+') as f:
while True:
data = self.s.recv(BUFFER_SIZE)
if not data: break # transfer finished
f.write(data)
size = os.path.getsize(filename)
self.conn.send(str(size)) # echo size
self.conn.send("success")
return
# do not close connection unless exception raised
def run(self):
self.conn()
while True:
try:
# shoud I connect again each time here?
self.recv()
except:
self.close()
break
and in the client I have,
# expected to establish a connection
def conn(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'client ready.'
try:
self.s.connect((self.ip, self.port))
print 'connection established.'
except:
# close socket
self.s.close()
raise
def send(self, msg='', flag=1):
if flag:
self.s.send(str(flag))
self.s.send(msg)
sent = self.s.recv(BUFFER_SIZE)
print sent
else:
self.s.send(str(flag))
self.s.send(msg) # send filename
# send file in buffer-size
with open(msg, 'rb') as f:
while 1:
data = f.read(BUFFER_SIZE)
if not data: break
self.s.send(data) # send block
sent = self.s.recv(BUFFER_SIZE)
print 'sent: %s bytes' % sent
The problem is, should I put client.socket.connect() in each send function or I just leave it established and trust it would not down? And in the server, should I close connection after each message received? And why my connection is mysteriously down after a short time?
Another question is I noticed some code examples transfer files from server to client using conn.send(), instead, I sent files from client to server by socket.send(). Will this cause a problem?
I think there is something wrong with function name which may cause your problem.
Change function name in your server code:
...
def connection(self):
...
...
def run(self):
self.connection()
while True:
...
Tell me if it works.