Error when attempting to read from a UDP socket - python-3.x

I create a UDP socket and send data to an address that is not listening. The next time I attempt to receive data, it fails with the error [WinError 10054] An existing connection was forcibly closed by the remote host. As an example, this code will error on the last line. Why and how can I fix it?
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(bytes("A", 'utf-8'), ("127.0.0.1", 5000))
s.recvfrom(128)

I create a UDP socket and send data to an address that is not listening
The answer is in the question. Just make sure that there is a server side logic to send you back data.
Otherwise the OS will send back to your app an ICMP message saying that there is nothing listening on that port, which will trigger the [WinError 10054] that you are reporting. BTW, UDP being in essence a connection-less protocol, the error message cannot be accurate.

Related

Python3: Is a write to UDP socket as file object even possible?

In Python3 I created a socket with s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) in order to send UDP to a certain destination in the network. Now the classical way would be to s.sendto(my_data, (ip, port)). But I would like to handle the socket as an io file object. Therefore I created one by f = s.makefile(mode='wb'). Now I can use f.write(my_data) to send data. But wait ... I never had to specify IP and port. Needless to say, the data does not arrive at the destination. With TCP there is no problem because with s.connect((ip, port)) I can specify ip and port before I create a file object.
Is it possible, and if yes how, to send UDP with a socket as file object?
okey...as I was writing the question it occurred to me that I could try calling s.connect((ip, port)) on the UDP socket although there is no connection to establish. VoilĂ  it works. Maybe this helps somebody.

The UDP socket cannot receive replies when connect function is used on Linux

I write a udp server and client using Python. The code is simple. When the udp client sends data to the server, the server replies a message to the client.
The server code is as follows, the filename is "serverudp.py".
#!/usr/bin/env python
from socket import *
HOST = ''
PORT = 19998
s = socket(AF_INET,SOCK_DGRAM)
s.bind((HOST,PORT))
print '...waiting for message..'
while True:
data,address = s.recvfrom(1024)
print data,address
s.sendto('this is the UDP server',address)
s.close()
The client code is as follows, the filename is "clientudp.py"
#!/usr/bin/env python
from socket import *
HOST='10.0.0.12'
PORT=19998
addr=(HOST,PORT)
s = socket(AF_INET,SOCK_DGRAM)
s.connect(addr)
while True:
message = raw_input('send message:>>')
s.sendto(message, addr)
data = s.recv(1024)
print data
s.close()
The client can not receive the any reply. However, if I comment the following
connect line in the client code, it works correctly.
#s.connect(addr)
As the same client code works well on another Linux machine with the connect line, so I want to know what's the problem with my Linux machine? Is there any Linux kernel restriction or TCP/UDP socket restriction with it?
I hope your answers, thank you!
You have an assumption in your code that may be incorrect. By passing 10.0.0.12 to connect, you are configuring your client to only accept incoming datagrams with a source IP address of 10.0.0.12. But nothing in your server either ensures that the source IP address is 10.0.0.12 or that the source IP address will match the destination address of the corresponding query.
Consider:
Client connects to 10.0.0.12:19998
Client sends datagram to 10.0.0.12:19998 with one of its IP addresses as the source address.
Server receives query sent to 10.0.0.12:19998.
Server forms response to the source IP address of that datagram and goes to send it.
Server chooses some source IP address other than 10.0.0.12 because it seems "closer" to the destination. The server's IP stack has no idea this datagram is in any sense a reply to the received datagram and so has no reason to set the source IP address to 10.0.0.12.
Client rejects the reply because it is connected to 10.0.0.12 and the reply is from some other IP address.
The short version of the solution is not to use connect for UDP unless the server is guaranteed to always send a reply datagram with a source IP address that matches the IP address the client is going to connect to. Nothing in your setup assures this.
The usual solution is to never bind a UDP socket to a wildcard IP address. Instead, bind the socket to the specific IP address the server is going to use to communicate with its clients.

Simultaneous TCP termination and subsequent connect(): EADDRNOTAVAIL

My company releases a special TCP stack for special purposes and I'm tasked with implementing RFC793 compliant closing sequence. One of the unit tests has a server working on top of the special TCP stack talking to a normal Linux TCP client, and I'm running into some strange behaviour that I'm not sure whether is caused by programming error on my part or is to be expected.
Before my work started, we used to send a RST packet when the user application calls close(). I've implemented the FIN handshake, but I noticed that in the case of simultaneous TCP termination (FIN_WAIT_1 -> CLOSING -> TIME_WAIT on both ends, see the picture), the standard Linux TCP client cannot connect to the same destination address and port again, with connect() returning with EADDRNOTAVAIL, until after TIME_WAIT passes into CLOSED.
Now, the standard Linux client application sets the option SO_REUSEADDR, binds the socket to port 8888 each time, and connects to destination port 6666. My question is, why does bind() succeed and why does connect() fail? I would have thought SO_REUSEADDR could take over a local TIME_WAIT port, which it did, but what does connect() have against talking to the destination-ip:6666 again?
Is my code doing something it shouldn't or is this expected behaviour?
I can confirm no SYN packet for the failed connect() makes it out of the client machine at all. I've attached a screenshot of the FIN handshake for the above session.
Your previous implementation used RST to end the connection. Receipt of an RST packet immediately removes the connection from the active connection table. That's because there is no further possibility of receiving a valid packet on that connection: the peer has just told your system that that session is not valid.
If you do a proper session termination with FIN, on the other hand, there is the last packet problem: how do you know for sure whether the peer actually received the last acknowledgment you sent to their FIN (this is the definition of TCP's TIME_WAIT state)? And if the peer didn't receive it, they might validly send another copy of the FIN packet which your machine should then re-ACK.
Now, your bind succeeds because you're using SO_REUSEADDR, but you still cannot create a new connection with the exact same ports on both sides because that entry is still in your active connection table (in TIME_WAIT state). The 4-tuple (IP1, port1, IP2, port2) must always be unique.
As #EJP suggested in the comment, it is unusual for the client to specify a port, and there is typically no reason to. I would change your test.

Why is my Socket Client not allowing the outgoing connection in python 3?

I have created a very simple UDP Socket client and server in python3.
I'm trying to send the simple message 'hello' to the server and I am getting the error:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
I'm not sure that it's actually the target machine's fault as the target machine is an AWS EC2 Ubuntu instance with 'All Traffic Allowed' configured with the security group.
I'm convinced it has to be some sort of outbound policy on my desktop computer...
Any help is appreciated.
Here is my code:
client.py
import socket
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(('servers public ipv4 ip', 8089))
client_sock.send('hello'.encode())
server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 8089))
s.listen(5) #5 connections
while True:
conn, addr = s.accept()
buffer = conn.recv(64)
if len(buffer) > 0:
print(buffer.decode())
break
First, despite your repeated claims (in body and tags) that you are using UDP you are actually using TCP as can be seen from your use of SOCK_STREAM and accept.
s.bind(('localhost', 8089))
You explicitly bind the server to localhost. But localhost is only the loopback interface of the computer (127.0.0.1) which is not reachable from outside. If you want to accept connections from other systems you need to either bind to the IP address of the specific network interface or broadly to 0.0.0.0 - or simply use s.bind('',8089).

difference between socket failing with EOF and connection reset

For testing a networking application, I have written an asio port "proxy": it listens on a socket for the application client activity and sends all incoming packets to another socket where it is listened to by the application server, and back.
Now when either the application or the server disconnect for various reasons, the "proxy" usually gets an EOF but sometimes it receives a "connection reset".
Hence, the question: when does a socket fail with a "connection reset" error?
A TCP connection is "reset" when the local end attempts to send data to the remote end and the remote end answer with a packet with the RST flag set (instead of ACK). This almost always happens because the remote end doesn't know about any TCP connection that matches the remote&local addresses and remote&local port numbers. Possible reasons include:
The remote end has been rebooted
A state-tracking firewall somewhere in the path has been rebooted/changed/added/removed
A load balancer has incorrectly directed the TCP connection to a different node than the one it was supposed to go to.
The remote IP address has changed hands (the new owner doesn't know anything about TCP connections belonging to the old owner).
The remote end considers that the TCP connection has been closed already (but somehow the local end doesn't agree).
Note that if the remote end answers the initial (SYN) packet in a TCP connection with a RST packet, it is considered "Connection refused" instead of "Connection reset by peer".

Resources