Sending messages via TCP sockets - python

I am making a code that the server sends from 1 to 256 kbytes to client. The client receives the message and must return it to the server. The process must be repeated 1000 times. The message is read from a file. The server is sending and the client is picking it up and sending it back, but at a certain moment it stops. I'd like to know what's wrong with my code.
Server:
import socket
hostA = '127.0.0.1'
portA = 50031
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind((hostA, portA))
dest = ('127.0.0.1',50008)
arquivo = 'texto.txt'
arq = open(arquivo , 'r')
arq = arq.read()
for i in range(0, 9):
dado = arq[0:(1024 * (2**i))]
for j in range(0, 1000):
for k in range(0, (len(dado) / 1024)):
x = dado[k:k+1024]
udp.sendto(x, dest)
for k in range(0, (len(dado) / 1024)):
msg, cliente = udp.recvfrom(1024)
udp.close()
Client:
import socket
hostB = '127.0.0.1'
portB = 50008
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind((hostB, portB))
orig = ('127.0.0.1',50031)
dado = ""
for i in range(0, 9):
for j in range(0, 1000):
for l in range(0, ((1024 * (2**i))/1024)):
msg, cliente = udp.recvfrom(1024)
dado += msg
for k in range(0, ((1024 * (2**i))/1024)):
x = dado[k:k+1024]
udp.sendto(x, orig)
udp.close()

Your question asks about "TCP sockets", but you aren't using TCP.
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.bind((hostA, portA))
You are using UDP. Unlike TCP, UDP does not detect lost packets or retransmit or re-order data.
Your protocol has no tolerance for packet loss. If a single packet from either the server to the client or the client to the server is lost, each side will wait for the other forever.
You have other issues too. Imagine if two datagrams sent by the client are received in the wrong order by the server. The data will be corrupted.
If you want to design on top of UDP rather than TCP, you have to implement yourself everything TCP provides that you need. If you need lost datagram detection and retransmission, you need to implement it yourself or use TCP. Ditto for transmit pacing, handling out of order reception, and so on.

Related

Python socket hangs on connect/accept

I'm trying to send packets using sockets, and was able to do so just fine until this morning. I'm not sure what's going on. The packets are showing up in tcpdump but the server and the client cannot connect to each other.
netcat.py
import socket
import argparse
import sys
import os
import re
import threading
def convertContent(content: str = "") -> bytes:
byteContent = []
# grab the hex from the content
for i in range(len(content)):
if content[i] == "\\" and content[i+1] == "x":
byteContent.append(f"{content[i+2]}{content[i+3]}")
# grab the non hex from the content, split it on the hex
stringContent = re.split(r"\\x.{2}", content)
byteIndex = 0
newContent = b""
# Re add the non-hex content, and the hex content
for word in stringContent:
newContent += word.encode()
if byteIndex < len(byteContent):
newContent += bytes.fromhex(byteContent[byteIndex])
byteIndex += 1
newContent = newContent.replace(b"\\n", b"\n").replace(b"\\r", b"\r")
return newContent
class Netcat():
'''
Netcat class that can be used to send/receive TCP packets
'''
BUFFER_SIZE = 1024
def __init__(self):
pass
#classmethod
def createSocket(cls):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Address might be in a TIME_WAIT status, ignore this
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Port might be in a TIME_WAIT status, ignore this
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
return sock
#classmethod
def send(cls, hostname: str = "127.0.0.1", srcPort: int = 0, destPort: int = 9999, content: str = "", buffer_size: int = 1024):
srcPort = int(srcPort)
destPort = int(destPort)
try:
content = convertContent(content=content)
except:
pass
sock = cls.createSocket()
# Set the source port before sending
sock.connect((hostname, destPort))
sock.sendall(content)
# shutdown might be redundant/unnecessary (tells connected host that we're done sending data)
sock.shutdown(socket.SHUT_WR)
while True:
data = sock.recv(buffer_size)
if len(data) == 0:
break
sock.close()
#classmethod
def receive(cls, port: int = 9999, buffer_size: int = 1024):
if port <= 1024 and os.geteuid() != 0:
print(f"Listening on port {port} requires superuser privileges!")
return
host = ""
sock = cls.createSocket()
sock.bind((host, port))
sock.listen(10)
conn, addr = sock.accept()
while True:
data = conn.recv(buffer_size)
if not data:
break
conn.close()
threading.Thread(target=Netcat.receive,daemon=True).start()
Netcat.send(content="test")
Note: I am sending the packets from one VM to another, rather than sending to myself, but it would be a lot to ask people to spin up a bunch of VMs to reproduce this. The hostname param in the send method should be the actual IP of the receiving machine
I've thrown some print statements, and the server stops on sock.accept(), while the client hangs on sock.connect((hostname, destPort))
I checked the hostname for the server, and it's listening on (0.0.0.0, 8888) (assuming 8888 is the port param), which means its listening on all interfaces on that port, so I dont know why its refusing to connect
I tcpdumped on the server, and its getting the packets, it gets a SYN, then sends out a SYN, ACK, but the rest of the packets are marked as re-transmissions.
I've tried looping the accept & connect lines, thinking maybe some sort of race condition was occurring, but no matter what I do the client can't connect to the server.
Edit: This works on my local machine, but still breaks when I try to send packets over the network. The first 2 steps of the handshake go through SYN & SYN, ACK, but not the third ACK
Don't bind in the client. Working example below, but minor changes to make a standalone script:
import socket
import threading
def receive(port: int = 9999, buffer_size: int = 1024):
host = ""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Address might be in a TIME_WAIT status, ignore this
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen()
conn, addr = sock.accept()
while True:
data = conn.recv(buffer_size)
if not data:
break
print(data)
conn.close()
def send(hostname: str = "127.0.0.1", destPort: int = 9999, content: str = b"test", buffer_size: int = 1024):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Address might be in a TIME_WAIT status, ignore this
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Removed bind
sock.connect((hostname, destPort))
sock.sendall(content)
# shutdown might be redundant/unnecessary (tells connected host that we're done sending data)
sock.shutdown(socket.SHUT_WR)
while True:
data = sock.recv(buffer_size)
if len(data) == 0:
break
sock.close()
threading.Thread(target=receive,daemon=True).start()
send()
Output:
b'test'

python udp broadcast sending but not receiving

I am trying a basic script that should be customized later on, but for now i need it to send a camera feed from a network connected raspberry Pi to multiple laptops on the same network.
I used udp streaming to a single device with the specific device address with the below code as a and it worked like a charm with no problem what so ever
sender
class FrameSegment():
""" this class inits the socket in the main file then sends the frames of a video in a loop with the udp_frame method """
MAX_IMAGE_DGRAM = 2**16 - 64 # minus 64 bytes in case UDP frame overflown
def __init__(self, port=5000):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # for linux use SO_REUSEPORT
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.s.settimeout(0.2)
self.PORT = port
def udp_frame(self, img):
compress_img = cv2.imencode(".jpg", img)[1]
dat = compress_img.tostring()
size = len(dat)
num_of_segments = math.ceil(size/(self.MAX_IMAGE_DGRAM))
array_pos_start = 0
while num_of_segments:
array_pos_end = min(size, array_pos_start + self.MAX_IMAGE_DGRAM)
msg = struct.pack("B", num_of_segments) + dat[array_pos_start:array_pos_end]
self.s.sendto(msg, ('192.168.1.110', self.PORT))
array_pos_start = array_pos_end
num_of_segments -= 1
Reciever
class RovCam():
""" inits the socket in main then reads the transmitted data from said socket in a loop to display the video """
MAX_DGRAM = 2**16 - 16
def __init__(self,port=5000):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # for linux use SO_REUSEPORT
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.s.bind(("", port))
self.dat = b''
self.dump_buffer()
print("ROV CAM : Connected successfully")
def dump_buffer(self):
while True:
seg, addr = self.s.recvfrom(self.MAX_DGRAM)
if struct.unpack("B", seg[0:1])[0] == 1:
break
def read(self):
seg, addr = self.s.recvfrom(self.MAX_DGRAM)
while struct.unpack("B", seg[0:1])[0] > 1:
self.dat += seg[1:]
seg, addr = self.s.recvfrom(self.MAX_DGRAM)
self.dat += seg[1:]
img = cv2.imdecode(np.fromstring(self.dat, dtype=np.uint8), 1)
self.dat = b''
return img
However The Problem is that if i change the address of the receiving device to a broadcast address like so
** in the sender file**
self.s.sendto(msg, ('192.168.1.255', self.PORT))
it stops working and the receiving device cannot read anything.
I then confirmed with the tcpdump tool that the receiver device is indeed receiving the sent stream over the specified port but the script has a hard time seeing that.
Turns out that it's a network error and when i removed the router from the network and made a smaller network with just a switch and an on board DHCP server on one of the devices used it handled the connection successfully

Client cannot receive UDP message

I am a beginner of socket programming using python. I am working on my course project. Part of my project requires sending and receiving UDP messages with different port. The server program called robot is provided and I need to write the client program called student which can interact with the robot. Thus, I cannot show all source code in the server program.
This is the part related to the UDP socket in the server program
############################################################################# phase 3
# Create a UDP socket to send and receive data
print ("Preparing to receive x...")
addr = (localhost, iUDPPortRobot)
s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s3.bind(addr)
x, addr = s3.recvfrom(1)
print ("Get x = %d" % (int(x)))
############################################################################# phase 3
time.sleep(1)
print ("Sending UDP packets:")
messageToTransmit = ""
for i in range(0,int(x) * 2):
messageToTransmit += str(random.randint(0,9999)).zfill(5)
print ("Message to transmit: " + messageToTransmit)
for i in range(0,5):
s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))
time.sleep(1)
print ("UDP packet %d sent" %(i+1))
############################################################################# phase 4
This is my client program. s3 is the UDP socket. I can send message to the server program successfully but I cannot receive the message from it. Is this due to the difference in the ports? If yes, what should I do in order to fix it?
import os
import subprocess
import socket
import random
import time
sendPort = 3310
localhost = '127.0.0.1'
socket.setdefaulttimeout(10)
command = "python robot_for_python_version_3.py"
subprocess.Popen(command)
print("ROBOT IS STARTED")
sendSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sendSocket.connect((localhost, sendPort))
studentId = '1155127379'
sendSocket.send(studentId.encode())
s_2Port = sendSocket.recv(5)
sendSocket.close()
s_2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s_2.bind((localhost, int(s_2Port)))
s_2.listen(5)
s2, address = s_2.accept()
s_2.close()
step4Port = s2.recv(12)
iUDPPortRobot, dummy1 = step4Port.decode().split(",")
iUDPPortStudent, dummy2 = dummy1.split(".")
s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
num = random.randint(5,10)
time.sleep(3)
s3.sendto(str(num).encode(), (localhost, int(iUDPPortRobot)))
print("Test1")
charStr = s3.recvfrom(1024)
print("Test2")
print(charStr)
exit()
The reason why you are not receiving the message is because the server sends it to an endpoint that is not listening for messages. As the protocol is UDP (no guarantees, etc.), the server sends the message successfully to a non-listening endpoint, while the listening endpoint waits forever.
In more detail, addr as returned by x, addr = s3.recvfrom(1) is not (studentIP, iUDPPortStudent). Try the following to see the difference (note that you have omitted the piece where iUDPPortRobot is defined and shared, I set it to 50000 for illustration purposes):
# in one interactive session 1 (terminal), let's call it session 1
>>> import socket
>>> import random
>>> import time
>>>
>>> iUDPPortRobot = 50000
>>> addr = ('localhost', iUDPPortRobot)
>>> s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s3.bind(addr)
>>> x, addr = s3.recvfrom(1) # <= this will block
# in another interactive session (terminal), let's call it session 2
>>> import socket
>>> import random
>>> import time
>>>
>>> iUDPPortRobot = 50000
>>> s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> num = random.randint(5,10)
>>> s3.sendto(str(num).encode(), ('localhost', int(iUDPPortRobot))) # <= this will unblock recvfrom in session 1, i.e., the message got received
1
# back to session 1
>>> addr <= check address, this is the main issue you are facing
('127.0.0.1', 60911)
>>> messageToTransmit = ""
>>> for i in range(0,int(x) * 2):
... messageToTransmit += str(random.randint(0,9999)).zfill(5)
...
>>> print ("Message to transmit: " + messageToTransmit)
Message to transmit: 06729020860821106419048530205105224040360495103025
# back to session 2, let's prepare for receiving the message
>>> charStr = s3.recvfrom(1024) # <= this will block
# back to session 1 to send a message
# you do not share what (studentIP,iUDPPortStudent), but from
# what you describe it is not ('127.0.0.1', 60911), let's say
# studentIP = 'localhost' and iUDPPortStudent = 50001
>>> studentIP = 'localhost'
>>> iUDPPortStudent = 50001
# now let send a message that will be sent successfully but not received, i.e.,
# it will not unblock recvfrom in session 2
>>> s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))
50
# ... but if try to send to the listening endpoint it will get received
>>> s3.sendto(messageToTransmit.encode(), addr)
50
# back to session 2, to check things
>>> charStr
(b'06729020860821106419048530205105224040360495103025', ('127.0.0.1', 50000)) # <= SUCCESS
There are two ways to fix this. The one shown above which involves changing the server code, which essentially involves what is shown above, i.e., send the message to a listening endpoint by modifying the address passed to s3.sendto. If I understand things correctly, this is not an option as you are trying to write the client code. The second way is to send the message to (studentIP, iUDPPortStudent), but have a listening endpoint at the other end. If studentIP and iUDPPortStudent are known to your "client" program, which I assume is the case, you can add code similar to what you have at the top of the server program code snippet.
Specifically, add in place of charStr = s3.recvfrom(1024) something like:
addr = (studentIP, iUDPPortStudent)
s4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s4.bind(addr)
charStr = s4.recvfrom(1024) # <= this will block and unblock when you send the message using s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))
For completeness, you will need to change localhost to 'localhost' and if in your experiments you encounter a OSError: [Errno 98] Address already in use you will have to wait for the TIME-WAIT period to pass or set the SO_REUSEADDR flag by adding s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) before bind.

Socket Programming three way handshake (PYTHON) with TCP

So I am working on a project that requires me to simulate a TCP three handshake protocol using UDP. I want to divided the project into two parts: the first is to establish and close connection; the second is to implement the flow control protocol without any package loss. Since the client and server will be interacting with each other, so I need two sockets, which means I also need two ports - 19990 and 19991 - to send and receive data between client and server.
I am having trouble with the three way handshake
Client -> (Send SYN)
Sever -> (Receive SYN and Send SYN ACK)
Client -> Receives SYN ACK and Sends ACK with Data
Server then establishes a connection and says that data has been received
Client -> Server ACK the connection & received data. So send FIN to close the connection
Server -> Receives FIN and closes the connection (with server_socket.close)
output on the client side:
Send: a,1
Receive: b, num:2
Send: c,3
Receive: d, num:4
Client done
output on server side:
Receive: a, num:1
Send: b,2
Receive c, num:3
Send: d,4
Server done.
However, what I am hoping for them to look like is like so:
client.py
Send SYN
Send: ,1
Receive: num,2
Received SYN-ACK. Send ACK & Data
Send: I love ABC University in New York City.,3
Receive: ,num:4
Received ACK for data. Send FIN. Connection closed.
Send: ,4
server.py
Receive: ,num: 1
Received SYN. Send SYN-ACK
Send: ,2
Receive: I love ABC University in New York City.,num:3
Receive ACK. Connection Established. Received Data. Send ACK
Send: ,4
Receive: ,num:4
Connection Closed
Here is the code I have for server.py:
import socket
import sys
import struct
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("0.0.0.0", 19990))
def send(c,num):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss = struct.pack("!50si",c.encode(),num)
s.sendto(ss,("127.0.0.1",19991))
s.close()
print("Send:%s,%d" % (c,num))
def recv():
global server_socket
data, addr = server_socket.recvfrom(1024)
str,num = struct.unpack("!50si",data)
str = str.decode("utf-8").replace("\0","")
print("Receive:%s,num:%d" % (str,num))
return str,num
while True:
str,num = recv()
num = num + 1
str = chr(ord(str)+1)
send(str,num)
if str == "d":
break
print("Server Done.")
server_socket.close()
Here is the code I have for client.py
import socket
import sys
import struct
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("0.0.0.0", 19991))
def send(c,num):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss = struct.pack("!50si",c.encode(),num)
s.sendto(ss,("127.0.0.1",19990))
s.close()
print("Send:%s,%d" % (c,num))
def recv():
global server_socket
data, addr = server_socket.recvfrom(1024)
str,num = struct.unpack("!50si",data)
str = str.decode("utf-8").replace("\0","")
print("Receive:%s,num:%d" % (str,num))
return str,num
str = 'a'
num = 1
while True:
send(str,num)
str,num = recv()
if str == "d":
break
str = chr(ord(str)+1)
num = num + 1
print("Client done.")
server_socket.close()
#If the number = 1, sender will send and the receiver will receive
#c is the data and num is the sequence number, for the first three msgs it is the flag
#The payload we want to send is seven characters with one sentence
#Window size is 4 with 4 being four characters
#First package is "i lo"
#I is sent as a package, then space as a package, then l as a package, and o as a package as a window
#First byte is i, second is space, l is third, o is forth.
#Send out 4 bytes, receive 4 acknowledgements.
#When the sender sends out the last byte "."
#To do: Change 'a' to past establishment
#Instead of Send: a, 1
#professor wants to see "Send Think message"
#Receive: Think ack message
#Send: Ack msg
#a b c d are just give you some examples

Unable to communicate with proxy/server application

I am having issue with below code in TCP python socket prog. I am trying to send integer messages from (lets say) 3 clients. So, There is 3 clients, so the proxy knows that N = 3, and it will wait until it receives 3 numbers. 1st client sends 10 to the proxy, 2nd client sends 20 to the proxy, and the 3rd client sends 30 to the proxy. Because N is reached, the proxy starts to transmit to the server. It will send (in order): 10, 20, 30, END (where every comma indicates a new message). The server receives the 4 messages, and after receiving the END message, it starts to calculate the average. The average is 20, so the server sends 20 to the proxy, and closes the connection. The proxy receives 20, and sends it to all the 3 clients, and then closes the connection. The clients receive 20.
Please check below code and let me know where I am making mistake... I am able to send number from client but not getting response from proxy/server. Am I doing any mistake ?
For client:
#!/usr/bin/env python
import socket
HOST = 'localhost'
PORT = 21001
proxysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proxysock.connect((HOST, PORT))
while True:
try:
data = str(raw_input())
except valueError:
print 'invalid number'
proxysock.sendall(data)
data = proxysock.recv(1024)
print 'server reply:' +data
proxysock.close()
For Proxy:
#!/usr/bin/env python
import select
import sys
import socket
from thread import *
HOST = 'localhost'
PORT = 21001
PORT1 = 22000
max_conn = 5
buffer_size = 2048
proxyserversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proxyserversock.bind((HOST, PORT))
proxyserversock.listen(max_conn)
input = [proxyserversock,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for proxysock in inputready:
if proxysock == proxyserversock:
client_sock, addr = proxyserversock.accept()
input.append(client_sock)
elif proxysock == sys.stdin:
junk = sys.stdin.readline()
running = 0
else:
data = proxysock.recv(buffer_size)
if data:
proxysock.send(data)
else:
proxysock.close()
input.remove(proxysock)
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.connect((HOST, PORT1))
serversock.sendall(data,END)
serversock.recv(buffer_size)
client_sock.sendall()
serversock.close()
client_sock.close()
For Server:
#!/usr/bin/env python
import socket
HOST = 'localhost'
PORT1 = 22000
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind((HOST, PORT1))
serversock.listen(10)
while 1:
serversock, addr = serversock.accept()
data = serversock.recv(2048)
data.pop()
average = float(sum(data))/len(data)
serversock.sendall(average)
print 'avg' + average
serversock.close()

Categories