If I have a UDP socket like so:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
and the socket can send data:
sock.sendto("message", address)
How do I find out the port of the socket - the port used when sending data to address?
EDIT: I tried sock.getsockname() but this raises an error: [Errno 10022] An invalid argument was supplied
I'm not too familiar with the python socket class, but based on what I've read here https://docs.python.org/2/library/socket.html#socket.getnameinfo
perhaps
socket.getnameinfo()[1] might work
since .getsockname() returns a 2-tuple (host, port)
The socket must be bound before you can use .getsockname() by doing sock.bind(('', 0)).
Hope this helps!
Related
I try to send messages in localhost to broadcast address, but it does not work. When I use socket.INADDR_BROADCAST, I get [Errno 11001] getaddrinfo failed.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_server.bind(("127.0.0.1", 12345))
client_server.connect((f"{socket.INADDR_BROADCAST}", 12345))
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))
You are creating a TCP (SOCK_STREAM) socket. TCP has no notion of broadcasting. A TCP client socket cannot connect() to a broadcast IP, and a TCP server socket cannot listen() on a broadcast IP. That just makes no sense to do. The only way to broadcast a message in TCP is for the server to keep track of each client connected to it and then send the message to each client one at a time.
A UDP (SOCK_DGRAM) socket, on the other hand, can sendto() a message to a broadcast IP (if you enable the socket's SO_BROADCAST option beforehand), and it can recvfrom() a message that was sent to a broadcast IP belonging to the adapter that the socket is bound to.
Just note that bind()'ing a broadcasting UDP socket to 127.0.0.1 means that only UDP receivers also bound to 127.0.0.1 will be able to receive the broadcasts. You won't be able to broadcast over the network.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#client_server.bind(("127.0.0.1", 12345))
client_server.setsockopt(client_server.SOL_SOCKET, client_server.SO_BROADCAST, 1)
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))
I'm trying to write a simple socket program to connect to the server using specific port. It works fine for the first time (it sends data using 127.0.0.1:8000 to server (127.0.0.1:6000)). However, when I rerun the code, I get below error:
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
Then after a while, it works again (just once). I think the socket is locked up and needs timeout because I'm not closing/shutdown socket properly but I'm not sure what I'm doing wrong. Any suggestion/comment would be greatly appreciated~!
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
server_address = ('127.0.0.1', 6000)
myIP = '127.0.0.1'
myPort = 8000
sock.bind((myIP,myPort))
sock.connect(server_address)
msg = 'test'
sock.sendall(msg)
sock.shutdown(socket.SHUT_RDWR)
sock.close()
I have a UDP communication between a server and client on localhost
according to this code:
https://pymotw.com/2/socket/udp.html
Echo Server:
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
sock.bind(server_address)
while True:
data, address = sock.recvfrom(4096)
if data:
sent = sock.sendto(data, address)
echo Client
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
message = 'This is the message. It will be repeated.'
try:
for i in range 4:
sent = sock.sendto(message, server_address)
data, server = sock.recvfrom(4096)
finally:
sock.close()
now let's say I got some MITM attack, and a specific packet doesn't arrive at the server, and the client is still waiting for a response from the server,
I get a deadlock.
how can I overcome this? is there some timeout parameter for UDP socket?
Yes, there is a timeout for UDP sockets. See socket.settimeout() in https://docs.python.org/2/library/socket.html and read up on non-blocking sockets in general.
Note that UDP packets can be dropped, duplicated, and/or re-ordered, even if there is no man-in-the-middle attacker. This is because UDP is (by design) an unreliable datagram protocol.
If you need a reliable protocol use TCP (or QUIC).
If you need assurance that no man-in-the-middle can modify or (optionally) observe the data, use TLS (or QUIC).
From the python library 'socket' is there a method that returns the IP of the socket that got binded to it?
Suppose a socket was declared and initialized like:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect(ip, port)
And I wanted to find the IP of a received datagram from a socket:
while True:
for s in socks:
recv = s.recv(1024)
#get ip of s or socket
#print received data from s.gethostname()
How would I go on about this?
you can try with recvfrom this method returns data and the address of the sender
data, address = sock.recvfrom(4)
Try with socket.getpeername().
Simple way would be like
data, (ip, port) = sock.recvfrom(4096)
print (ip)
This following is a straightforward IPv4 UDP broadcast, followed by listening on all interfaces.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
sock.bind(("", 1337))
sock.sendto("hello world", ("255.255.255.255", 1337))
while True:
data, addr = sock.recvfrom(0x100)
print "received from {0}: {1!r}".format(addr, data)
I want to adjust this to send and receive both IPv4 and IPv6.
I've poked around and read as much as I can and believe the following is roughly the route I need to take:
Create an IPv6 socket.
Add the socket to a link or site local multicast group.
Send the UDP packets to the multicast address for the group in use.
Further info I have is that I may need to bind to several interfaces, and tell the socket using setsockopt() that it should also receive multicast packets. Lastly getaddrinfo() can be used across the board to gracefully "drop back" to IPv4 where IPv6 isn't available.
I have much of this implemented, but stumble primarily on the multicasting parts. A complete code example in Python, or vivid description of the constants and addresses needed are preferred.
Here's a link to python mcast demo, does both IPv4 and IPv6.
I'm currently asking a question over here that involves getting the multicast address of a received message, but the source code answers your question!
To listen:
# Initialise socket for IPv6 datagrams
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Allows address to be reused
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Binds to all interfaces on the given port
sock.bind(('', 8080))
# Allow messages from this socket to loop back for development
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
# Construct message for joining multicast group
mreq = struct.pack("16s15s".encode('utf-8'), socket.inet_pton(socket.AF_INET6, "ff02::abcd:1"), (chr(0) * 16).encode('utf-8'))
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
data, addr = sock.recvfrom(1024)
and to send:
# Create ipv6 datagram socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Allow own messages to be sent back (for local testing)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
sock.sendto("hello world".encode('utf-8'), ("ff02::abcd:1", 8080))
This is for python3.6, with python 2.7 I don't think the encodes are necessary. Also in the struct.pack line, I've seen variations of "16s15s" such as "4s", but I don't know what it is and what I have worked for me!