This is the configuration I am using.
Now I want the nodes to send packets in broadcast, but only to nodes directly connected.
sender.py:
import socket
import time
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
server.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
server.settimeout(0.2)
message = b"mymessage"
while True:
server.sendto(message, ('<broadcast>', 37020))
print("message sent!")
time.sleep(1)
receiver.py:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
client.bind(("", 37020))
while True:
data, addr = client.recvfrom(1024)
print(f"received: {data}, from: {addr}\n")
Let's say this is the configuration:
If I run receiver.py on r1,r2,r3, and I run sender.py on r4, i would expect to receive the messages only on the directly connected machines, since I set TTL=1. Instead I receive the message in ALL machines. The output of the receiving machines is received b"mymessage" from 172.17.0.4 (which is the interface I use to manage the virtual nodes, as seen in the picture. Since I don't want the nodes to use that interface, I tried to replace the <broadcast> parameter in sender.py with a more specific one. I first replaced it with 10.255.255.255, but I couldn't receive anything. 0.0.0.0 is not working either. I have a similar issue using multicast, but that would go out of topic. I am probably doing something very wrong here but i can't figure out what.
The final aim, as partially stated above, is to give each nodes the ability to connect ONLY to the adjacent ones, skipping anything that requires more than 1 hop.
Thank you for your time.
Related
I am currently trying to use Socket to multicast audio in real time to an IP and Port.
import socket
MCAST_GRP = '000.0.0.00'
MCAST_PORT = 00000
MULTICAST_TTL = 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
with open('C:\\Users\\User\\Downloads\\dog_bark_x.wav', 'rb') as f:
for l in f:
sock.sendto(sock.sendall(l), (MCAST_GRP, MCAST_PORT))
sock.close()
I am currently testing this by using a WAV file. however when i run the code I receive this 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 can send strings without error using code below, meaning the client is connected and listening so im not sure why i am encountering the error above:
import socket
MCAST_GRP = '000.0.0.00'
MCAST_PORT = 00000
MULTICAST_TTL = 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto("Test".encode(), (MCAST_GRP, MCAST_PORT))
sock.sendto(sock.sendall(l), (MCAST_GRP, MCAST_PORT))
The inner sock.sendall(l) is working on the unconnected socket, that's why the error. It is likely that you did not mean to use sendall here at all but simply
sock.sendto(l, (MCAST_GRP, MCAST_PORT))
Note though that you are using UDP here which is an unreliable protocol, i.e. datagrams might be lost, duplicated or reordered during transmit. You thus cannot expect that the data will be read by the recipient exactly as they were sent.
Apart from that it is not a good idea to use for line in file when reading binary data.
I am working on a test tool for an existing piece of SW that outputs messages on multicast ip of 240.240.240.1 port 2349. The IP interface on which I am receiving the multicast messages is 192.168.0.4. I can observe these messages being pushed out onto the network via wireshark. Even netstat -ng shows the subscriptions. However, the receiver I wrote in python is not picking them up. I did borrow the code below from another thread, with the attempt to modify it to work in my situation.
import socket
import struct
import sys
multicast_group = '240.240.240.1'
server_address = (multicast_group, 2345)
# Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind to the server address
sock.bind(server_address)
# Tell the operating system to add the socket to
# the multicast group on all interfaces.
group = socket.inet_aton(multicast_group)
src = bytearray(socket.inet_aton("192.168.0.4"))
mreq = bytearray(group)
mreq.extend(src)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
mreq)
# Receive/respond loop
while True:
print('\nwaiting to receive message')
data, address = sock.recvfrom(1024)
print('received {} bytes from {}'.format(
len(data), address))
print(data)
print('sending acknowledgement to', address)
sock.sendto(b'ack', address)
Any help would be appreciated in figuring out what I am doing wrong.
So I figured out my own problem. I had checked iptables as being an issue early on, with no luck. But I fixed/modified several things along the way to address the issues being seen. Turns out the code above works just fine, it was firewalld/iptables rules blocking the receipt of multicast.
I'm ultimately trying to test a UDP client, and want to make sure that it works when sending data not through the loopback interface, to avoid any subtle issues this introduces, such as differences in checksum validation (Bad UDP checksum has no effect: why?).
However, even when sending data to the result of socket.gethostbyname(socket.gethostname()), which is not 127.0.0.1, then according to Wireshark, the data seems to go via the loopback interface.
The below program sends and receives b'somedata' successfully, and has the below capture from Wireshark.
import asyncio
import socket
async def server():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setblocking(False)
sock.bind(('', 4567))
data = await loop.sock_recv(sock, 512)
print('Received', data)
async def main():
local_ip = socket.gethostbyname(socket.gethostname())
print('Local IP', local_ip) # Outputs 192.168.0.34
asyncio.ensure_future(server())
await asyncio.sleep(0)
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setblocking(False)
sock.connect((local_ip, 4567))
await loop.sock_sendall(sock, b'somedata')
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
How can I send data from a client running locally, to a server running locally, but avoiding the loopback interface and actually sending data out into the network?
Ideally answers would be applicable to both Linux and macOS.
To 'convince' the networking stack to physically transmit the frame using the Ethernet (or WiFi) card rather than the loopback, use a broadcast address.
I have successfully sent and received an UDP packet this way on my Linux system. I verified it with tcpdump. It shows one packet on Ethernet interface and no activity on loopback.
I have used literal broadcast address. The socket module documentation mentions also the string '<broadcast>' as a special case address. I did not tried it.
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setblocking(False)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.connect(('192.168.0.255', 4567))
await loop.sock_sendall(sock, b'somedata')
await asyncio.sleep(1)
Notes:
other hosts on the same network will receive the UDP packet as well.
make sure the firewall/packet filter (e.g. Linux iptables/nftables) will not block the packet.
regarding the setsockopt: Python socket.error: [Errno 13] Permission denied
That's probably because your hostname is pointing to the loopback address hence socket.gethostbyname(socket.gethostname()) will yield 127.0.0.1
What you need to do is cancel that pointing from the hostname to the loopback address:
in Linux edit the /etc/hosts and comment out the line 127.0.0.1 YOUR_HOSTNAME
in Windows you should have c:\windows\system32\drivers\etc\hosts which looks similar to the Linux one
After this if you call the socket.gethostbyname(socket.gethostname()) it will yield your DHCP assigned IP.
Though even in this case, calling from yourip to yourip might result in the network driver to route the package through the loopback interface. Alternative would be to use the public IP, outside your network router. You could use an external service as described in this answer
I want to implement tcp check with Python.
I found a magic way in this article.
It introduce a efficient way to do a tcp-health-check.
Client: SYN
Server: SYN-ACK
Client: RST
I also found a Go implementer https://github.com/tevino/tcp-shaker.
But i hope to implement SYN,SYN-ACK,RST in python.
My code is there:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_TCP, socket.TCP_QUICKACK, 0)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 0)
s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
s.connect((ip, port))
s.close()
But it didn't work as I expected. The client send a ACK to the server when the SYN-ACK received from server.
How could I disable TCP_QUICKACK in Python?
This topic has been covered in a good amount of detail here, unfortunately, I'm still running into some trouble.
I'm trying to subscribe to a stream of motion-capture data from a windows box on my network. The mo-cap server is broadcasting over my network, and I can pick up the data with wireshark on my OS X machine ('the target'). I see that a message originating from the origin ip 204.102.224.2 (windows) broadcasting on 239.255.42.99 via UDP, to port 1511 is going out, as desired.
My python code is as follows:
PORT = 1511
MULTICAST_ADDRESS = '239.255.42.99'
SOCKET_BUFSIZE = 1024
datasock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
datasock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
datasock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
datasock.bind((MULTICAST_ADDRESS, PORT))
mreq = struct.pack("=4sl", socket.inet_aton(MULTICAST_ADDRESS), socket.INADDR_ANY)
datasock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
datasock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
datasock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, SOCKET_BUFSIZE)
datasock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while 1:
data = datasock.recv(rx.MAX_PACKETSIZE)
packet = rx.unpack(data, version=version)
if type(packet) is rx.SenderData:
version = packet.natnet_version
#print("NatNet version received:", version)
if type(packet) in [rx.SenderData, rx.ModelDefs, rx.FrameOfData]:
packet_dict = packet._asdict()
all_bodies = packet_dict['rigid_bodies']
for body in all_bodies:
contortion = body._asdict()['orientation']
euler = Quat([elem for elem in contortion]).equatorial
I think for my current issue it is safe to ignore some of the code in the loop, as some of it derives from a helper library I'm using (optirx). Note that I didn't start out with all the options, but decided to include all of them to see what should stay and what can go. I've tried various combinations and permutations. I'm on OS X 10.10.3
The problem is here:
datasock.bind((MULTICAST_ADDRESS, PORT))
You shouldn't bind the socket to the multicast address. You should bind it to '0.0.0.0'. The setsockopt call with IP_ADD_MEMBERSHIP takes care of joining the multicast group.