Basic UDP networking doesn't receive - python-3.x

I'm trying to learn UDP networking so I tried the simplest code to begin with. It's a python code client-server that works perfectly when I send data to localhost or to the LAN IP from the same computer, but it doesn't work when I try to send from my computer using the public IP, and also doesn't work from another computer using private network IP or public IP.
I did the port forwarding, created the input rules for windows firewall, turned off the router internal firewall, and it still doesn't work.
When I scan my port from canyouseeme.org or using netcat it says connection refused and port closed.
Maybe somebody can guess what is happening here or what may I do to succeed?
I write the code below in case it's needed.
Server:
import socket
UDP_IP = "0.0.0.0"
UDP_PORT = XXXX
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
message = data.decode()
print("received message:", message)
Client:
import socket
UDP_IP = "192.168.1.133"
UDP_PORT = XXXX
MESSAGE = "Hello, World!"
print("UDP target IP:", UDP_IP)
print("UDP target port:", UDP_PORT)
print("message:", MESSAGE)
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE.encode(), (UDP_IP, UDP_PORT))
Thanks in advance.

After some investigation I have found a partial solution. I'm posting an answer because it may help some people with similar problems, but it's not the best solution yet, so the issue is still there.
I found that there's no problem in communicating within a LAN if I completely disable the firewall in both computers. I don't know why the input rules or exceptions don't work.
For networking beyond the LAN I have tried successfully to use a virtual LAN (i.e. hamachi) and there's no necessity of port forwarding nor disabling the firewall. The bad thing about hamachi is that I don't control the protocol it uses, and I don't control the way of ensuring reliability.
For the applications I'm dealing with right now I probably have enough with this solution, but it would be interesting to know more.

Related

Why is "connection refused" error occuring

This is client.py class and This class is on mobile.
import socket
c = socket.socket()
c.connect(('127.0.0.1', 9998))
name = input("Enter your name : ")
c.send(bytes(name, 'utf-8'))
data = c.recv(1024).decode()
print(data)
This is server.py class and This class is on mac book pro.
import socket
s = socket.socket()
s.bind(('localhost', 9998))
s.listen(2)
print('server is waiting for connections..')
while True:
c, addr = s.accept()
name = c.recv(1024).decode()
print('connected with', addr, name)
st = "Hello, " + name
c.send(st)
c.close()
Why am I getting "connection refused" error?
Your client and server are running on different devices. Your client is trying to connect to the local loopback IP 127.0.0.1, which will work only if the server is running on the same device as the client. That is why you are getting "connection refused" - there is no server listening locally at 127.0.0.1:9998.
If the client and server are connected to the same network (WiFi, etc), the client needs to connect to the server's actual LAN IP on that network.
If the client and server are connected to different networks (ie, they reach each other over the Internet), the client needs to connect to the public IP of the network that the server is connected to, and that network router will need to have port forwarding configured to route incoming connections to the server device.
Also, note that making the server listen on localhost does not guarantee it will be able to accept clients from other devices, depending on how localhost is implemented. It might resolve to 127.0.0.1 only. The server should instead listen on the wildcard IP 0.0.0.0 so it listens on all available network interfaces that are installed on that device. Or, it can alternatively listen on just the specific LAN IP that will actually be receiving the client connections.
To echo what Remy just correctly said, "connection refused" is really a bit misleading. It basically means that there was no one listening at the address-and-port that the host tried to reach. It does not mean that "there was someone there, but he [actively ...] 'refused to' talk with you." "Connection failed" might have been a better term, but, here we are.

How to send a message between 2 computers

I have looked into many tutorials and source code for pythons socket modal to try to send a simple string between two computers.
I have made my code work independently on the PCs, but have failed to get the code to run on both. Here is the code I am currently working with:
#server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), 1234))
s.listen(5)
while True:
# now our endpoint knows about the OTHER endpoint.
clientsocket, address = s.accept()
print(f"Connection from {address} has been established.")
clientsocket.send(bytes("Send test","utf-8"))
clientsocket.close()
#client.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), 1234))
while True:
full_msg = ''
while True:
msg = s.recv(8)
if len(msg) <= 0:
break
full_msg += msg.decode("utf-8")
if len(full_msg) > 0:
print(full_msg)
I am running the client script on both computers, but when I run the script on the pc not running the server, I get error the connection refused error [#10061]. I am running python 3.7, one pc is a laptop connected via internet, and one is a desktop connected to a router via Ethernet cable.
If someone knows what I need to change to get the program to run correctly, it would be much appreciated.
I am a rookie in python but I have experience in networking. Your problem sounds like a network issue to me. Before you run your program, you have to make sure there is connectivity between the two computers as you mentioned a laptop in the internet. Best way to know is pinging to each other. Your problem sounds like a typical NAT (network address translation issue).
I think you didn't open your '1234' port in your firewall.
https://www.windowscentral.com/how-open-port-windows-firewall
If you are using windows, this link can help you

UDP connection refused

This is what I am trying to do:
I have a windows computer and a Linux computer (ubuntu 16.10) connected to the same wireless router. The router is not connected to the Internet, as this might raise some security concerns (and we don't want the windows computer to talk to the net).
The windows computer is running a program that is supposed to stream data to an UPD port (say port 1234). Using the Microsoft TCPView utility I can see that the windows machine opens the port. In fact, it should allow connections from any IP address and any port (that's what the *'s mean in TCPView).
View of the TCPView Utility
When I try to find the open port on the windows machine from the Linux computer using nmap this is what happens:
Starting Nmap 7.01 ( https://nmap.org ) at 2017-01-30 16:50 EST
Nmap scan report for 192.168.0.164
Host is up (0.051s latency).
PORT STATE SERVICE
1510/udp open|filtered mvx-lm
MAC Address: 74:DE:2B:D8:26:24 (Liteon Technology)
At the very least, this tells me that the linux machine can see the windows machine (I can also ping it). However, I am not sure about the open|filtered state of the port. According to the Nmap manual:
Nmap places ports in this state when it is unable to determine whether
a port is open or filtered. This occurs for scan types in which open
ports give no response. The lack of response could also mean that a
packet filter dropped the probe or any response it elicited. So Nmap
does not know for sure whether the port is open or being filtered. The
UDP, IP protocol, FIN, NULL, and Xmas scans classify ports this way.
When I try to connect to the port using Python, an error occurs. This code
import socket
UDP_IP = "192.168.0.164"
UDP_PORT = 1234
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
results in an error 'connection refused'. A little C++ client program that is supposed to read out the streamed data also fails to connect to the port. I am using Python now to test the accessibility of the port more quickly.
In contrast, connecting to TCP port 8080 works fine. Also, I have been sending data back and forth over TCP through the same router between other machines and using a range of ports.
Other important info:
The same errors occur if I switch off the firewall and virus scanner on the windows machine
I have added UDP port 1234 as an allowed connection in the advanced firewall settings of windows.
So, my questions are:
Does anybody have any suggestions about how to debug/solve this situation?
What's different between UDP and TCP that would cause TCP to work without a hiccup (in my past projects) and causes UDP to give me nightmares?
You are forgetting that UDP is not a connection-based protocol. It is a datagram protocol.
There is no way to distinguish between a server that is receiving UDP packets but not responding to them, from a server which is behind a firewall which drops those packets. This is why nmap is describing a port as open|filtered -- there is no way for it to tell the difference.
Your call to sock.bind is failing because you are trying to bind (that is, to start listening for packets!) to a port on a remote IP. This is impossible in general.
It turns out that my problems were two-fold
1) I did have a bad understanding of the UDP protocol. That's been rectified by the answers in the forum. For anyone interested in how to use UDP and Python to communicate between two computers, see this recipe: http://code.activestate.com/recipes/578802-send-messages-between-computers/
2) The windows program that I was trying to communicate with can not be used to to send data over UDP through wifi. Why? I don't know. I called the developer and that's what he told me.
Current status: the problem is not solved but is diagnosed as a combination of my lack of knowledge and an ideosyncratic windows program (see my original post above)
You are trying to bind to a non-local IP address. Use 0.0.0.0 instead of the target address you're using, and connect() or sendto() the target address.

Create a virtual serial port connection over TCP

I am developing an application that should be able to write to a virtual serial port and receive data through the same port from remote clients over network.
The application runs on a linux server. I am new in using serial ports and I have some questions on this topic.
Clients
The client can establish a TCP connection to a server. When we setup a client, we have to provide the IP address of the server, a tcp port (usually 8080) and a virtual com port.
The client then will automatically try to connect to the server.
Server
The server has a virtual com port, the same we set in the client config (e.g. COM1). When an application on the server writes data to this port, the data should be send to all clients connected via tcp. The response from the clients is send over TCP back to the server which can read it over the virtual serial port.
Question
On windows I used a virtual serial port connector http://www.eterlogic.com/Products.VSPE.html which did most of the work. However I want to solve this problem on linux machines.
My question is, how can I create a TCP server that has a virtual serial port attached and can send/receive data through this port over TCP to listening clients?
Try socat. Possible scenario:
socat pty,link=/dev/virtualcom0,raw tcp:192.168.254.254:8080&
socat creates TCP connection to 192.168.254.254:8080, so that everything, that will be written to /dev/virtualcom0 will be forwarded to 192.168.254.254:8080 and vice versa.
Another approach would be to use RFC2217 via ser2net on Linux sever side and RFC2217 driver on Windows side (for example http://www.hw-group.com/products/hw_vsp/index_en.html single port version). You can also try to get http://pyserial.sourceforge.net/ to work with ser2net.
you have socat and ser2net and other programs but my experience is very bad... not working properly. I've done this small python program, can be useful. Update port, baudrate... then use any tcp client. Remove first line if don't want to use is as auto executable script
#!/usr/bin/python
import socket
import sys
import serial
#open serial port
ser = serial.Serial('/dev/ttyAMA0', 115200, timeout=0)
#create socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
#bond to the port. Don't use localhost to accept external connections
server_address = ('', 2105)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
#listen
sock.listen(1)
#loop
while True:
#waits for a new connection
print('waiting for a connection')
connection, client_address = sock.accept()
try:
print('connection from', client_address)
#continously send from serial port to tcp and viceversa
connection.settimeout(0.1)
while True:
try:
data = connection.recv(16)
if data == '': break
ser.write(data)
except KeyboardInterrupt:
connection.close()
sys.exit()
except Exception as e:
pass
received_data = ser.read(ser.inWaiting())
connection.sendall(received_data)
except Exception as e:
print e
finally:
#clean up connection
connection.close()
The software will help to establish server and client connection over TCP http://www.serial-com-port.com/
I use it for creating virtual serial communications over network, but I have the real RS232 port on the computer. So I just transfer the data over network. If you need to create a virtual COM on the server too, use the Virtual Serial Port Driver.

Receiving UDP broadcast packets on Linux

We have existing software that periodically broadcasts UDP packets to a specific port (7125) on the local subnet (x.x.x.255). We have monitoring software running on HP-UX (11.11) that is able to receive these packets no problem. However, after porting the monitoring software to Linux (RHEL 6.1) we have found that it does not receive the broadcast packets. tcpdump shows the packets arriving at the Linux host, but the kernel does not send them through to our software.
I've been using a couple of python 2.x scripts that mimic the socket API calls the monitoring software uses to test different scenarios. The Linux kernel passes the packets to the receiver software if the sender uses unicast (10.1.0.5), but not broadcast (10.1.0.255). I've been searching the web for several days and have not found anyone with the same problem. Any ideas?
receiver.py
from __future__ import print_function
import socket
localHost = ''
localPort = 7125
remoteHost = '10.1.0.5'
remotePort = 19100
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
print('Listening on {0}:{1} for traffic from {2}:{3}'.format(localHost, localPort, remoteHost, remotePort))
data = s.recv(1024)
print('Received: {0}'.format(data))
s.close()
sender.py
from __future__ import print_function
import socket
import time
localHost = ''
localPort = 19100
remoteHost = '10.1.0.255'
remotePort = 7125
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
data = 'sending this from {0}:{1} to {2}:{3}'.format(localHost, localPort, remoteHost, remotePort)
print(data)
print('2')
time.sleep(1)
print('1')
time.sleep(1)
s.send(data)
print('sent at {0}'.format(time.ctime()))
s.close()
Well, I suggested this answer in a comment, and it proved correct in practice. I would like to investigate surrounding nuances further with my own code, but this is the canonical case-closer.
In addition to setting the SO_BROADCAST socket option on both sides (as you are already correctly doing), you must also bind your receiver to the broadcast address (e.g., INADDR_BROADCAST, which is 255.255.255.255 and essentially serves the same role as INADDR_ANY for unicast).
Apparently, in the HP-UX configuration of the original poster, a UDP socket bound to a unicast address (or INADDR_ANY, specifically) but with the SO_BROADCAST socket option set will still receive all UDP datagrams addressed to the local broadcast address as well as unicast traffic directed at the host.
Under Linux, this is not the case. Binding a UDP socket, even when SO_BROADCAST-enabled, to INADDR_ANY is insufficient to receive both unicast and broadcast datagrams on the bound port. One can use a separate INADDR_BROADCAST-bound SO_BROADCAST socket for the broadcast traffic.

Resources