I am trying to write a python program that will spawn multiple clients to speak to one server on the network. My question is what do I need to do to simulate different IP addresses for each client?
I am using MAC OSX Lion right now with Python 2.6.
I have already developed the server side that can accept multiple sockets. I want to avoid having a machine for each client. Any tips/hints for a newbie would be appreciated.
Even though this is an old question, it still appears in google...
As already mentioned, basically it will take the IP the connection is received from and assigns the next available port... So with a standard socket.. you will end up with a bunch of connections from the same IP with varying ports.
Personally to me its easier to create a client script that will generate the amount of clients you need (i'm using 1000+ clients from a single python script)..
Once you have the clients generated, have the script generate a IP for each of the clients.. If your handling your connection objects correctly.. You can always refer back to which client you want..
So in the end, you have all the clients coming from the same machine or another on the network but you simply have variable with a random/generated IP address which you can test with.. It takes only a few lines to use the generated IP address as a reference to your socket object.
If you are wanting to work with something IP specific like only allow a connection from a particular subnet.. Simply generate the fake IP address at the time of the connection and use it as if it was the real one.
If you are just wanting to have multiple clients, no need to generate a IP address at all as everything is a different port.
Extract for example purpose:
for i in xrange(1, self.iCount + 1):
if len(self.objClients) >= self.iCount:
break
#Generate a uid ... sID = xxxxxx+i
if sID not in self.objClients:
oPosData = []
self.objClients[i] = {"id":sID, "current":0, "connected":True}
for oT in self.objClients:
try:
self.objClients[oT]['socket'] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.objClients[oT]['socket'].connect((self.ServerIP, self.ServerPort))
self.objClients[oT]['timer'] = time.time() + randint(0, 10)
http://docs.python.org/library/socket.html#socket.create_connection
If supplied, source_address must be a 2-tuple (host, port) for the socket to bind to as its source address before connecting.
I think that should do it.
Related
So far I have made a VERY basic client/server application that creates a TCP connection. I have a lot of programming experience, just never did this low-level stuff and especially nothing with networks. Note that all the prints are just to help me figuring out what is going on. One of the known issues is that jsonip sometimes gives me an IPv4 and sometimes v6, I don't know why but that doesn't matter for now, just to warn anyone who wants to recreate my code.
Server:
import socket
import requests
port = int(input("Enter port you want to open:\n"))
#todo: add errorhandling
print("Adding socket...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
hostname = socket.gethostname()
print(f"Hostname: {hostname}")
ip_address = socket.gethostbyname(hostname)
print(f"Host address: {ip_address}")
r = requests.get(r'http://jsonip.com')
public_ip_address = r.json()['ip']
s.bind((ip_address, port))
print("Is open for connections on IP: "+public_ip_address+" and Port: "+str(port))
s.listen(5)
print("Done initialisation, listening for incoming connections...")
while True:
clientsocket, address = s.accept()
print(f"Connection from {address} has been established")
clientsocket.send(bytes(f"You have connected to server: {hostname}", "utf-8"))
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip = input("Enter IP to connect to:\n")
port = int(input("Enter Port to connect to:\n"))
print(f"Connecting to server {ip} ...")
s.connect((ip, port))
msg = s.recv(1024)
print(msg.decode("utf-8"))
On my local machine: Open 20000 in my server.py, it tells me the host is 127.0.1.1, I then enter 127.0.1.1 into my client script and 20000, and they connect. So the Socket has been bound with the 127.0.1.1. (Side question: What is this IP address, is it like the internal IP address of processes in my PC or something? If running ip a on my other machine it is the first one shown of 2)
Using Virtmanager on my machine and running one Linux Server (command line only) and one normal Ubuntu, the server tells me the host is, again, 127.0.1.1 which I don't need to enter into the other VM to know it won't work, what does work however, is getting the IP-address of the Server via ip a, which in this case is 192.168.122.37, and when I enter this IP address into the client, it connects. But in the socket here I bind, again, the 127.0.1.1, so is it arbitrary what I put here? What SHOULD I bind here, the public, the weird or the 192. address?
The first thing I could not get to work was using 2 physical devices. When opening a server on my Linux machine, I cannot connect with my windows machine at all, no matter if I use my public, my 127. or my 192. IP-address. Now my end goal is doing this over the internet so I am walking myself up, describing here the steps I took to try and get where I want to be but here I hit a brick wall where I don't know what is wrong. Am I binding the wrong address on the server, is my router being a problem, is there something else wrong?
I also tried leaving my network using my friends pc a few countries over, but this also just results in a timeout (my theory is that the Router port he is trying to open is closed and I have now idea how I can make the router send data to his PC, which should be not impossible as firefox and every application using internet does it without me having to manually forward every port, I just don't know how). This is my end goal, creating a connection between my friends PC and mine, and this is how far I got (I wouldn't mind skipping the local network if it is not relevant for fixing the global connection problem), so, tl;dr: what did i do wrong, what do i need to bind and what do i need to do for the final result to work?
There are many questions to answer.
Addresses 127.X.X.X are reserved for the loopback interface, most common one is 127.0.0.1. The loopback is a virtual, but important interface and as you have probably guessed, it is usable on the local machine only. You cannot use 127.X.X.X address to make two hosts to communicate with each other.
Addresses 192.168.X.X (and also 10.X.X.X and 172.16-31.X.X.) are reserved for local LANs. They are not valid on the Internet.
You cannot use these addresses to make two hosts to communicate with each other over the public Internet (unless you create a tunnel, an advanced networking topic)
Almost everybody uses them, because we ran out of IPv4 addresses long time ago, they were difficult to get, expensive, etc. Also such hosts are isolated from the Internet, they can be reached only via a router that translates addresses. Such router feature is called NAT. A typical router has one valid Internet address and all connections to the Internet appear as coming from the router. If you contant a service like jsonip.com from a PC, you get your router's address, not your PC's address.
See also: Finding local IP addresses using Python's stdlib
To make your program working, make it to accept connections on all interfaces. See the first example in the socket docs. On Linux, use port numbers >= 1024. Ports < 1024 are reserved, not available to regular users.
Final point is that a firewall may prevent connections to your server. It depends on your system and setup.
So currently I am trying to send udp to a server with a web domain like this
www.example.com/path?stuff=exist
I am currently trying to use socket
and this is is an example of my code
import socket
IPADDR = '64.233.177.139'
that is the ip of google, and not the ip I am currently trying to send to
PORTNUM = 9001
PACKETDATA = '42["message","test"]'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
s.connect((IPADDR, PORTNUM, '/path?stuff=exist'))
s.send(PACKETDATA)`
And I currently get this error
TypeError: getsockaddrarg() takes exactly 2 arguments (3 given)
I am new to using the socket library and did some digging to no avail.
For some more context I just want to send the data in PACKETDATA to the server google.com/path?stuff=exist (not really that url, just an example)
Anything helps, thanks in advance.
Your immediate programming problem is that socket.connect expects to be called with an argument that is a tuple containing exactly two items -- a hostname (or IP address) string and a port number. But this program passes an argument tuple that contains 3 items -- a host address, a port number and the string '/path?stuff=exist'. That's why the error message complains about finding 3 things where only 2 were expected.
If you want to send '/path?stuff=exist' over UDP then you'll have to include it in the data portion of the datagram. You'll also have to come up with some way of making it distinguishable from the PACKETDATA that you're already putting into the datagram body. (That doesn't need to be fancy. You could just insert a space between the path string and the PACKETDATA.)
There might also be a conceptual problem here. A web server only listens for TCP traffic. It does not listen for UDP traffic. So unless you've arranged for your specific server to have some sort of listener accepting datagrams on the target UDP port, nothing at the server side will collect this traffic even after you've figured out how to get Python to send it.
I'm new to the world of networking and wanted to clarify some of my thoughts regarding a problem I am facing at the moment. I saw this post which makes me think what I'm doing may be impossible, but I thought it would be worth a shot to ask on here and see what more qualified people think about it.
I am a TA for an intro computer science course, and I am writing a final project for students to complete at the end of the semester. Essentially, the project would be to fill in the holes in the implementation of a messaging client. I have set it up so each client would run two threads (one to listen for incoming messages, and one to wait for input to send messages to the other client). I have gotten this to work successfully on localhost with communication between two different port numbers, and am trying to find a way to have this work over the network so the two clients do not necessarily have to be on the same machine.
After struggling through a few methods, I came up with this solution: I would host a server on Heroku that would keep track of the clients' IPs and port numbers, and use a rest API so that one client could easily get the IP and port of the other client they are trying to communicate with. I have tested this, and the API seems to work. Thus, a client can create a socket endpoint and send it to this server to be entered into its database, and when the communication is terminated, it is removed from the database (this JSON would store a username as the primary key and internally manage an IP and port number) as the connection is now closed.
So, what I have is each client with an IP and port number knowing the IP and port number it is trying to communicate with. My last struggle is to actually form the connection. I understand there is a distinction between localhost (127.0.0.1) and the public IP for an internet endpoint. Upon searching, I found a way to find the public IP for the current user to share with the database, but I cannot bind to it. Whenever I try to, I get sockets error code 13: permission denied. I would imagine that if I tried connecting to the public IP of the other machine, I would get a similar error (but I cannot test the client until I can get a server running!).
I read online that some router work would be needed to actually form this connection between two machines. I guess I'm struggling to understand the practicality of socket programming if such a simple operation (connecting two socket endpoints on two different computers) requires so much tweaking. Is there something I am missing?
For reference, here is a general outline of my code thus far. The server:
# Server thread
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((LOCAL_IP, AVAILABLE_PORT))
s.listen(1)
# In my code, there is a quitting mechanism which closes s as well.
while True:
client_socket, addr = s.accept()
data = client_socket.recv(1024)
print "Received: " + data
client_socket.close()
...and the client:
# Client thread
# It is an infinite loop so I am always waiting for another potential message to send
while True:
x = raw_input()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((OTHER_MACHINE_LOCAL_IP, OTHER_PORT))
sock.sendall(x)
sock.close()
Right now, I cannot make progress with these permission denied errors. Is there any way I could get this to work? Understand that, being that this would be for around 250ish students to use who are all intro CS students, I would want to avoid having to instruct them to do anything with their routers.
If there is another method to do this which would make this easier that I am missing, I would also love to hear any suggestions :) Thanks in advance!
An eye-tracking application I use utilizes UDP to send packets of data. I made a python socket on the same computer to listen and dump the data into a .txt file. I already have this much working.
A separate application also written in python (what the eye-tracked subject is seeing) is running on a separate computer. Because the eye-tracking application is continuous and sends unnecessary data, so far I've had to manually parse out the instances when the subject is looking at desired stimuli. I did this based on a manually synchronized start of both the stimuli and eye-tracking applications and then digging through the log file.
What I want to do is have the second computer act as a second UDP client, sending a packet of data to the socket on the eye-tracking computer everytime the subject is looking at stimuli (where a marker is inserted into the .txt file previously mentioned). Is it possible to have a socket listening to two IP addresses at one time?
Here's my socket script:
#GT Pocket client program
import datetime
import socket
now = datetime.datetime.now()
filename = 'C:\gazelog_' + now.strftime("%Y_%m_%d_%H_%M") + '.txt'
UDP_IP = '127.0.0.1' # The remote host (in this case our local computer)
UDP_PORT = 6666 # The same port as used by the GT server by default
sock = socket.socket(socket.AF_INET, #internet
socket.SOCK_DGRAM) #UDP
sock.bind( (UDP_IP, UDP_PORT) )
while True:
data, addr = sock.recvfrom( 1024) #I assume buffer size is 1024 bytes.
print "Received Message:", data
with open(filename, "a") as myfile:
myfile.write(str(data + "\n"))
sock.close()
myfile.close()
EDIT:
#abarnert I was able to bind to the host address on the Ethernet interface and send a message from computer B to computer A, but computer A was no long able to receive packets from itself. When I specified UDP_IP = '0.0.0.0' computer B was no longer able to send data across the Ethernet. When I specified UDP_IP = '' I received the `error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
This have to do with the script I used on the Computer B to send the data:
import socket
UDP_IP = "169.254.35.231" # this was the host address I was able to send through.
UDP_PORT = 6666
MESSAGE = "Start"
print ("UDP target IP:"), UDP_IP
print ("UDP target port:"), UDP_PORT
print ("message:"), MESSAGE
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT) )
I didn't know where (or if at all) I needed to specify INADDR_ANY, so I didn't. But I did try once where import socket.INADDR_ANY but got ImportError: No module named INADDR_ANY
Seems like a simple issue based on your response, so I'm not sure where I'm messing up.
EDIT2: I just reread your answer again and understand why socket.INADDR_ANY doesn't work. Please disregard that part of my previous edit
EDIT3: Okay so the reason that I wasn't picking up data when specifying the host IP was that the application I was collecting data from on Computer A was still specified to send to 127.0.0.1. So I figured it out. I am still curious why 0.0.0.0 didn't work though!
No. A socket can only be bound to a single address at a time.*
If there happens to be a single address that handles both things you want, you can use a single socket to listen to it. In this case, the INADDR_ANY host (0.0.0.0) may be exactly what you're looking for—that will handle any (IPv4) connections on all interfaces, both loopback and otherwise. And even if there is no pre-existing address that does what you want, you may be able to set one up via, e.g., an ipfilter-type interface.
But otherwise, you have to create two sockets. Which means you need to either multiplex with something like select, or create two threads.
In your case, you want to specify a host that can listen to both the local machine, and another machine on the same Ethernet network. You could get your host address on the Ethernet interface and bind that. (Your machine can talk to itself on any of its interfaces.) Usually, getting your address on "whatever interface is the default" works for this too—you'll see code that binds to socket.gethostname() in some places, like the Python Socket Programming HOWTO. But binding to INADDR_ANY is a lot simpler. Unless you want to make sure that machines on certain interfaces can't reach you (which is usually only a problem if you're, e.g., building a server intended to live on a firewall's DMZ), you'll usually want to use INADDR_ANY.
Finally, how do you bind to INADDR_ANY? The short answer is: just use UDP_IP = '', or UDP_IP = '0.0.0.0' if you want to be more explicit. Anyone who understands sockets, even if they don't know any Python, will understand what '0.0.0.0' means in server code.(You may wonder why Python doesn't have a constant for this in the socket module, especially when even lower-level languages like C do. The answer is that it does, but it's not really usable.**)
* Note that being bound to a single address doesn't mean you can only receive packets from a single address; it means you can receive packets from all networks where that single address is reachable. For example, if your machine has a LAN connection, where your address is 10.0.0.100, and a WAN connection, where your address is 8.9.10.11, if you bind 10.0.0.100, you can receive packets from other LAN clients like 10.0.0.201 and 10.0.0.202. But you can't receive packets from WAN clients like 9.10.11.12 as 10.0.0.100.
** In the low-level sockets API, dotted-string addresses like '0.0.0.0' are converted to 32-bit integers like 0. Python sometimes represents those integers as ints, and sometimes as 4-byte buffers like b'\0\0\0\0'. Depending on your platform and version, the socket.INADDR_ANY constant can be either 0 or b'\0\0\0\0'. The bind method will not take 0, and may not take b'\0\0\0\0'. And you can't convert to '0.0.0.0' without first checking which form you have, then calling the right functions on it. This is ugly. That's why it's easier to just use '0.0.0.0'.
I believe you can bind a raw socket to an entire interface, but you appear to be using two different interfaces.
It's probably best to use two sockets with select().
How to create multi-server sockets on one client in Python ?
I am thinking about create a List of server socket and make the connection with
non-blocking socket, but i don't find a good tutorial for that, thats why i came here,
to ask for better solution or a guide for non-blocking socket.
Thank you !
Thank for the help, but i mean to something different, i have list of Servers Ip like that:
SERVER_IP = ['127.0.0.1', '127.0.0.2', '127.0.0.3', '127.0.0.4', '127.0.0.5', '127.0.0.6, '127.0.0.7']
I have one option to create a list of sockets by ip, and try to connect to every Ip Server, but i ask
here if i have a different way to connect to all this Servers Ip without a list of sockets, something more convenient.
Thank you.
If you want to have multiple sockets connected to multiple servers, you should check out the select module (http://docs.python.org/2/library/select.html).
Basically, it works like this:
import socket, select
socks = {}
# Connect to different servers here #
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socks[sock1.fileno()] = sock1
poll = select.poll()
for sock in socks:
poll.register(sock)
while 1:
fd, event = poll.poll() # Optional timeout parameter in seconds
sock = socks[fd]
sock.recv(1024) # Do stuff
A note, the poll.poll() method returns the underlying file number (what your operating system uses to represent files) which is useless to you. I just stores the sockets in a dictionary by that number so you could get the actual socket object from the filenumber that is given by poll. I recommend reading the documentation for select.poll, the link above.
You can use select.
http://pymotw.com/2/select/ plus the select documentation.
Or some third party module such as twisted.