I am trying to learn about network communications and sockets. Here is some code that I wrote:
Client code:
from socket import *
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind('127.0.0.1', 3000)
data, addr = sock.recvfrom(1024)
print "Received data '" + data + "' from address:", addr
Server code:
from socket import *
sock = socket(AF_INET, SOCK_DGRAM)
sock.sendto("HELLO WORLD", ('127.0.0.1', 3000))
sock.close()
The client prints out: Received data 'HELLO WORLD!' from address: ('127.0.0.1', 60788)
To my understanding, the second member of the tuple is supposed to be the port. Furthermore, if I send several messages the number increase by 1 every time. Why is it not 3000?
As a side-note, are the htons and htonl functions necessary with the python API?
First of all: The scripts that you've written here would typically be regarded as a server and client, respectively, not client and server. This is because the server (the first script) is binding to a known port and waiting for a connection, while the client (the second script) is connecting to it from a random port and sending data.
To answer your questions directly:
Since you aren't binding the client to any specific port, it's choosing a new epheremal port for each socket, and those are being used sequentially. If the server were to send a packet back to that same host and port, it would be received by the client.
The htons and htonl functions are not generally necessary in Python. The socket module takes care of endian-swapping addresses and port numbers for you.
The port you are seeing is the port the data was sent from, not the port the data was sent to. When you don't specify the source port, and your "server" doesn't, the system assigns the socket a source port.
Related
First of all I am not talking about a tcp or udp or socket implemented in a vps or server
My question is just like client to client socket communication.
Imagine listening at your home pc with a tcp socket. You can connect to this from home inter network anyway. But suppose someone wants to connect to it via the internet. Then you can create a forwarding rule on the router and bring it to working condition. Then the router knows that if an incoming connection comes from a port, the connection will be forwarded to the device in the relevant inter network.
But the ISP I use does not support port forwarding.
I thought these were not impossible because of the team-viewer software. Because when I was connected to a friend in team-viewer, I opened the wire-shark and reviewed it.
Then I saw that the data packet is exchanged peer to peer. Because the destination source addresses were my ip and friend's ip
This means that the video data is exchanged without the participation of an additional server
I highlighted the team-viewer connection.
61.245.175.81 is my friend's public IP. 192.168.1.130 is my internal IP
I want to do the same
Here is my simple socket code. This does not work through the internet because there is no router forwarding rule. I am very new to socket and networking side
Sever
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('', 12000))
while True:
message, address = server_socket.recvfrom(1024)
message = repr(message)
print("Connected from -> " + str(address) )
print("Received data -> " + message)
reply = b"Hi from server :) "
server_socket.sendto(reply, address)
Client
import time , datetime
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.settimeout(1.0)
message = bytes(str(datetime.datetime.now()),'utf-8')
addr = ("192.168.1.130", 12000)
client_socket.sendto(message, addr)
try:
data, server = client_socket.recvfrom(1024)
print( repr(data) )
except: #socket.timeout:
print('REQUEST TIMED OUT')
Can anyone give an explanation for my question
Pretty sure they do it using UDP hole punching, you'd need to do something similar to implement this.
In a nutshell two clients behind NAT (which is what your router is doing) can use a third server acting as a sort of mediator to establish a connection.
I am writing a UDP server application that serves as a back end to Teltonika FMB630 car mounted devices.
I already took care of the protocol specifics and decoding, the problem I am facing relates to the UDP socket used.
My UDP server has to send an acknowledgement to the client device upon receiving a message (that is the protocol), however, if I send those ACKs, the server socket stops receiving data after a while.
The server's UDP socket object is passed to an concurrent.futures.ThreadPoolExecutor that fires a function (send_ack) that sends the ACK, however this is not the issue because I tried calling send_ack in the main thread, after receiving data and the same issue occurs.
I suspect the problem is the remote device somehow breaks the connection or the ISP or MNO doesn't route the reply packet (this is a GPRS device) and then the socket.send() method that is used to send the acknowledge, somehow freezes other socket operations, specifically recvfrom_into called in the main thread loop.
I wrote two scripts to illustrate the situation:
udp_test_echo.py :
#!/usr/env/bin python
import socket
import concurrent.futures
def send_ack(sock, addr, ack):
print("Sending ACK to {}".format(addr))
sock.connect(addr)
print("connected to {}".format(addr))
sock.send(ack)
print("ACK sent to {}".format(addr))
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("127.0.0.1", 1337))
data = bytearray([0] * 10)
executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)
while True:
print("listening")
nbytes, address = s.recvfrom_into(data)
print("Socket Data received {} bytes Address {}".format(nbytes, address))
print("Data received: ", data, " Echoing back to client")
executor.submit(send_ack, s, address, data[:nbytes])
udp_test_client.py:
#!/usr/env/bin python
import socket
import time
import random
def get_random_bytes():
return bytearray([random.randint(0,255) for b in range(10)])
ip = "127.0.0.1"
port = 1337
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((ip, port))
while True:
stuff_to_send = get_random_bytes()
print("Sending stuff", stuff_to_send)
s.sendall(stuff_to_send)
print("reply: ", s.recvfrom(10))
time.sleep(0.1)
Running udp_test_echo.py in one terminal and udp_test_client.py in another, we see normal operation but if you Ctrl+C the test client and re run it, you will see that the server doesn't respond until it is restarted.
Is there a way to timeout a specific sending operation from a specific call to socket.send() method without affecting other calls ? (I want my socket.recvfrom_into call to block on the main thread)
If I settimeout on the entire socket object, I am going to have to deal with many exceptions while waiting for data in the main thread and I don't like to have to rely on exceptions for proper program operation.
The culprit was the socket.connect() call in send_ack, when being called on the server's socket object it causes the socket to no longer be bound and listen on the port specified in the start of the program.
Instead the send_ack function was changed to be:
def send_ack(sock, addr, ack):
print("Sending ACK to {}".format(addr))
sock.sendto(ack, addr)
print("ACK sent to {}".format(addr))
socket.sendto(data, address) uses the existing connection instead of starting a new one.
I'm using the socket module from Python 3.7 (shouldn't matter, as I tried activating a different Python version from different venv's).
The problem is that I've created a TCP connection listening at port 65432, an arbitrary number that I selected for this simple demo.
server.py looks like the following:
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Non-privileged ports are > 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
client.py is relatively straightforward as it makes a connection with 127.0.0.1:65432.
import socket
HOST = '127.0.0.1' # The server's hostname or IP address
PORT = 65432 # Port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# Send its message and then read the server's reply and prints it
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
Executing server.py to open the port 65432 for listening (in first console) and then executing client.py to send a simple 'hello world' message (in a second console). This is what got printed to the first console:
Connected by ('127.0.0.1', 56051)
So far so good. Port 56051 connecting to port 65432, right? No.
I execute netstat -am (command tool utility to see state of sockets on the host machine) and found this:
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.51495 *.* LISTEN
Instead of 127.0.0.1.65432 as local address, it is using port 51495 instead.
Doing another verification check, this time firing off lsof -i -n:
COMMAND PID FD TYPE DEVICE SIZE/OFF NODE NAME
Code\x20H 51214 37u IPv4 0x1af15eb424ba89f3 0t0 TCP 127.0.0.1:51495 (LISTEN)
Both verifications confirmed that port 51495 is being used instead of 65432 as specified in my server.py and client.py scripts. Any leads or tips? Many thanks in advance!
65432 is the port number of your server socket, not your client socket. As the client end is not attached with any specific port number, it will be dynamically allocated with port number, every time you run the client code.
As far as I understood, you mentioned -
Connected by ('127.0.0.1', 56051)
is shown on the first console which is your server console. so this port number is port number of client socket. not the server socket.
In the server code, you are using, s.accept(), this function returns the connection temporary id and the address of the client which made the request. same thing you are trying to print in the code.
As #ottomeister pointed out, the process name was the first giveaway. The process name should have been Python but it showed VS Code instead, which is indicative that the port 51495 is opened by the VS Code process and has nothing to do with our socket module code.
The way the context manager was setup means that the connection will be closed the moment the last line (in this case, socket.sendall()) is executed. So the server socket is not active anymore.
I run netstat after the client socket has connected, by this point the server port is closed.
When I monitor the ports status while the server port is open (before the client socket connects with it) then sure enough 65432 is what appeared. This is confirmed in netstat, lsof and also nmap. A simple print statement after the socket connection is successful will also confirmed that the server port is in fact using the specified port number, which is 65432.
Sorry for the inconvenience, and again much appreciation to Ottomeister for first pointing this out.
I'm trying to run the below program but I keep getting connection error's:
from socket import *
from codecs import decode
HOST = 'localhost'
PORT = 5000
BUFSIZE = 1024
ADDRESS = (HOST, PORT)
server = socket(AF_INET, SOCK_STREAM)
server.connect(ADDRESS)
dayAndTime = decode(server.recv(BUFSIZE), 'ascii')
print(dayAndTime)
server.close()
ERROR: ConnectionRefusedError: [Errno 61] Connection refused
Any idea what's going on?
If your book doesn't mention the other half of sockets, you need a better book.
Socket basics are easy. You have one process listen on a port, waiting for connections. Commonly we'll call this a 'server'. Another process (perhaps on the same machine, perhaps remote) attempts to connect to that port. We'll call that the client.
If no one is listening, then when the client attempts to connect they'll get your error Connection Refused.
So, set up a listening process. Below, on the left is server code; on the right is client code. Top-to-bottom is the "flow".
server = socket(AF_INET, SOCK_STREAM) # <- just like your example
server.bind(ADDRESS) # rather than 'connect', we 'bind' to the port
server.listen(1) # bind "claims" the port, so next we call listen & wait...
# Meanwhile...
# Your client process
client = socket(AF_INET, SOCK_STREAM)
client.connect(ADDRESS)
# It's only at this moment that the client reaches across the network to the server...
# On connect, the listening server wakes up, and needs to "accept" the connection
(s, remote_addr) = server.accept()
Once accepted, you can now send/recv on the s socket on the server-side, and send/recv from the client socket on the client side. Note that the server variable is not the socket to communicate on -- it's used to listen for new connections. Instead, you read/write on the socket object returned as first item of accept().
There's lots more to consider but this is at the heart of the Internet and has been pretty much unchanged since the 1980s.
Image from wikipedia entry for Berkeley Sockets:
I have set up a server socket (plain raw socket) listening on port A. A client now connects to this server. OS opens up a port for the client for this purpose. Say port B is allocated to this client. Now my question is, can a 3rd script connect to this port B and send data. Or in other words can I spoof a response to the client as if it was coming from the server? I tried spoofing it using scapy, but it wasnt working.
server.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", A))
s.listen(10)
ns, cli_addr = s.accept()
time.sleep(30) # so that i can trigger my 3rd script
goodclient.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", A))
print s.getsockname() # to get the local port of client - B
s.recv(1024)
badboy.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", B)) # connection refused error
s.send("hihihi")
scapybadboy.py
pack = IP(src="localhost", dst="localhost") / TCP(sport=A, dport=B) / "Hello"
send(pack) # Packet sent but not received by the client
Because server and client using SOCK_STREAM sockets, they both aware of TCP session(including port, IP and (SEQ_NUMBER,ACK_NUMBER)), so when session is already in process, you will have to perform TCP hikacking and IP spoofing in order to send messages in stream.
In other words, you will have to guess(or steal) ACK number of server in order to send fake messages to client using badclient.
However, if you will make somehow goodclient answer you and not a server you should run the following:
iptables -A FORWARD -j NFQUEUE --queue-num 1 , because your operating system doesn't know about session that you just "opened" with goodclient and it will send RST packet. This command will prevent it.