Python Requests, how to specify port for outgoing traffic?
requests
is built on urllib3
, which offers the ability to set a source address for connections; when you set the source address to ('', port_number)
you tell it to use the default host name but pick a specific port.
You can set these options on the pool manager, and you tell requests
to use a different pool manager by creating a new transport adapter:
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
class SourcePortAdapter(HTTPAdapter):
""""Transport adapter" that allows us to set the source port."""
def __init__(self, port, *args, **kwargs):
self._source_port = port
super(SourcePortAdapter, self).__init__(*args, **kwargs)
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(
num_pools=connections, maxsize=maxsize,
block=block, source_address=('', self._source_port))
Use this adapter in a session object, the following mounts the adapter for all HTTP and HTTPS connections, using 54321
as the source port:
s = requests.Session()
s.mount('http://', SourcePortAdapter(54321))
s.mount('https://', SourcePortAdapter(54321))
You can only set the one source port, limiting you to one active connection at a time. If you need to rotate between ports, register multiple adapters (one per URL) or re-register the catch-all mounts each time.
See the create_connection()
utility function documentation for the details on the source_address
option:
If
source_address
is set it must be a tuple of(host, port)
for the socket to bind as a source address before making the connection. An host of''
or port0
tells the OS to use the default.
Set port for outgoing TCP requests in Python?
This question is not Python specific but a design issue. A server application should not need any static information about possible clients.
If you need information from the client, one of the first actions after the initial handshake between server and client is to exchange the needed information from a client to a server.
E.g.
- Server starts listening on Port 3000
- Client connects to Port 127.0.0.1:3000
- Client starts listening on Port 4000
- Client sends port 4000 to the Server and awaits its connection
Setting host and port for requests.Session() objects
From the requests
documentation about sessions:
The Session object allows you to persist certain parameters across
requests. It also persists cookies across all requests made from the
Session instance, and will use urllib3’s connection pooling. So if
you’re making several requests to the same host, the underlying TCP
connection will be reused, which can result in a significant
performance increase (see HTTP persistent connection).
So while you give the url each time. Under the hood requests will not be creating a new TCP socket connection for each request. It will reuse the TCP socket connection to this host and port from the connection pool.
The main idea behind sessions is to share parameters and cookies between each request without having to set them individually in each request. and under the hood it will persist the connection. but you still need to give the full URL in each call
Send http request through specific network interface
I found a way using pycurl
. This works like a charm.
import pycurl
from io import BytesIO
import json
def curl_post(url, data, iface=None):
c = pycurl.Curl()
buffer = BytesIO()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.POST, True)
c.setopt(pycurl.HTTPHEADER, ['Content-Type: application/json'])
c.setopt(pycurl.TIMEOUT, 10)
c.setopt(pycurl.WRITEFUNCTION, buffer.write)
c.setopt(pycurl.POSTFIELDS, data)
if iface:
c.setopt(pycurl.INTERFACE, iface)
c.perform()
# Json response
resp = buffer.getvalue().decode('UTF-8')
# Check response is a JSON if not there was an error
try:
resp = json.loads(resp)
except json.decoder.JSONDecodeError:
pass
buffer.close()
c.close()
return resp
if __name__ == '__main__':
dat = {"id": 52, "configuration": [{"eno1": {"address": "192.168.1.1"}}]}
res = curl_post("http://127.0.0.1:5000/network_configuration/", json.dumps(dat), "wlp2")
print(res)
I'm leaving the question opened hopping that someone can give an answer using requests
.
Related Topics
Why Xgrabkey Generates Extra Focus-Out and Focus-In Events
"E: Unable to Locate Package Python-Pip" on Ubuntu 18.04
How to Obtain Ports That a Process in Listening On
Pip Install Unable to Find Ffi.H Even Though It Recognizes Libffi
How to List All Python Virtual Environments in Linux
Automatic Detection of Display Availability with Matplotlib
How to Convert .Pcm Files to .Wav Files (Scripting)
How to Properly Write to Fifos in Python
Asyncio in Corroutine Runtimeerror: No Running Event Loop
Get File Creation Time with Python on Linux
How to Setup Environment Variable R_User to Use Rpy2 in Python
What Are Python Pandas Equivalents for R Functions Like Str(), Summary(), and Head()
How to Convert Index of a Pandas Dataframe into a Column