Python Socket UDP WinError 10040 - python

I'm trying to stream JSON data over UDP to another computer. For this i created this simple class. It does work but after a while i get the OS error:
OSError: [WinError 10040] A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself
My packet size are around 128 bytes but is send them +- 20 time a second. The bigger the packet the faster i get this error. The also happends when on the recieving side nothing is connected.
What am i doing wrong?
import socket
import json
class JSON_UDP:
def __init__(self,send_ip='127.0.0.1', send_port=7002):
self.send_ip = send_ip
self.send_port = send_port
self.sender = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP
def send(self,input,send_ip='127.0.0.1', send_port=7002):
self.send_ip = send_ip
self.send_port = send_port
self.input = input
data = json.dumps(self.input)
data = bytes(data,encoding="utf-8")
print(len(data))
self.sender.sendto(data, (self.send_ip, self.send_port))
Tried it set a buffer size but without succes
self.buff_size = 1024
self.sender.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,self.buff_size)
self.sender.bind(('0.0.0.0',0))

Related

Sending image with socket causing that the image doesnt show correnclty

I wanted to write a program that allows me to send an image from a client to a server and to write this server and this client:
Server:
import io
import struct
import socket
from PIL import ImageFile, Image
def server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 3999))
server_socket.listen(1)
print('Server is listening on port 3999')
while True:
ImageFile.LOAD_TRUNCATED_IMAGES = True
client_socket, address = server_socket.accept()
print('Connection from: ', address)
image = Image.open(io.BytesIO(client_socket.recv(1024)))
image = image.resize((640, 480), Image.ANTIALIAS)
image.save("transfer/image.jpg")
client_socket.close()
if __name__ == '__main__':
server()
and this is the client:
import socket
import io
from PIL import Image
def Client():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("localhost", 3999))
byteImgIO = io.BytesIO()
byteImg = Image.open("old.jpeg")
byteImgIO.seek(0)
byteImg.save(byteImgIO, format="JPEG")
byteImgIO.seek(0)
client.send(byteImgIO.read())
client.close()
if __name__ == '__main__':
Client()
print("File sent to server")
This is the image:
Image to send
This is the output:
Image received
what did i wrong?
The problem is that your image is incomplete. There are at least two issues:
first, you only try to read 1024 bytes in the client. Your image may be larger than that and you may get fewer than 1024 bytes anyway. So you need to read until you get the correct number of bytes, and you probably want to send a 4-byte network byte-order size in bytes as the first part of your frame so the client knows how many bytes to read. Remember TCP is a continuous stream, not packets or messages. The receiver needs to be told how many bytes to read.
secondly, the sender already has a JPEG-encoded file on disk. There is no need to decode it from JPEG to turn it into a PIL Image then re-encode to a JPEG inside a BytesIO to send it. Just open the disk file in binary mode, read it and send what you read.
You can see a very similar example over serial here to get an idea of reading a JPEG and sending the frame size.
The recvall() function here shows a way of receiving a specific number of bytes on a socket in a loop.

Recvall with while loop doesn't work between two devices in python

I have the following problem: I want a sever to send the contents of a textfile
when requested to do so. I have writen a server script which sends the contents to the client and the client script which receives all the contents with a revcall loop. The recvall works fine when
I run the server and client from the same device for testing.
But when I run the server from a different device in the same wifi network to receive the textfile contents from the server device, the recvall doesn't work and I only receive the first 1460 bytes of the text.
server script
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("", 5000))
server.listen(5)
def send_file(client):
read_string = open("textfile", "rb").read() #6 kilobyte large textfile
client.send(read_string)
while True:
client, data = server.accept()
connect_data = client.recv(1024)
if connect_data == b"send_string":
send_file(client)
else:
pass
client script
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("192.168.1.10", 5000))
connect_message = client.send(b"send_string")
receive_data = ""
while True: # the recvall loop
receive_data_part = client.recv(1024).decode()
receive_data += receive_data_part
if len(receive_data_part) < 1024:
break
print(receive_data)
recv(1024) means to receive at least 1 and at most 1024 bytes. If the connection has closed, you receive 0 bytes, and if something goes wrong, you get an exception.
TCP is a stream of bytes. It doesn't try to keep the bytes from any given send together for the recv. When you make the call, if the TCP endpoint has some data, you get that data.
In client, you assume that anything less than 1024 bytes must be the last bit of data. Not so. You can receive partial buffers at any time. Its a bit subtle on the server side, but you make the same mistake there by assuming that you'll receive exactly the command b"send_string" in a single call.
You need some sort of a protocol that tells receivers when they've gotten the right amount of data for an action. There are many ways to do this, so I can't really give you the answer. But this is why there are protocols out there like zeromq, xmlrpc, http, etc...

Dividing udp datagram messages

i am trying to send a message through UDP (a list of dictionaries that i used json.dumps on it) and i get this error:
OSError: [WinError 10040] A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself
This is the client side code:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = (SRVR_NAME,DST_PORT)
packet_info = json.dumps(packet_info)
packet_info = packet_info.encode()
sock.sendto(packet_info,server_address)
sock.close()
and this is the server side code:
listening_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = (IP, PORT)
listening_sock.bind(server_address)
client_msg, client_addr = listening_sock.recvfrom(MSG_SIZE)
d = json.loads(client_msg)
d = d.decode()
print(d)
My psychic powers suggest you are trying to put more than 64KB of data into a single UDP packet.
Maximum size of an IP packet including all headers is 65535 bytes. IP and UDP headers combine for at least 28 bytes. So the max size of the data portion of a UDP datagram is 65535-28 == 65507.
Check the size of your encoded packet_info before sending. If it's too big to fit, then split into multiple messages and handle accordingly.

send large raw packet with python

I'm trying to develop a serial to ethernet bridge (half-duplex/rs485) in python.
The maxium allowed size of ethernet frames is 1536 bytes, but the maximum size of raw frames I can send from python is 1500 bytes. I don't know how to solve that.
Here is a part of my code which is sending the received frames to ethernet.
def ethernet_send(self):
"""
ethernet send thread
sends received data over ethernet
"""
# Init the Ethernet Socket
send_socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
send_socket.bind((self.config["interface"], 0))
while True:
# get next frame
ethernet_frame = self.send_ethernet.get()
# un escape data
ethernet_frame = self.un_escape(ethernet_frame)
# send data
send_socket.send(ethernet_frame)

Python sends malformed UDP Packets

I am having trouble receiving UDP packets on an Android device, so I want to find out if I am sending them properly. Using Wireshark, everytime I try to send a UDP packet to a remote address, the following error message occurs:
232646 311.898009000 172.56.16.78 192.168.0.3 UDP 64 Source port: 31947 Destination port: 5001 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]
Frame check sequence: 0xf5b6d06d [incorrect, should be 0xb0c869e3]
Does anyone know how to fix this? Would this be the cause of why I could not receive UDP packets on my Android device?
Server Code:
import http.server
import socket
import threading
import socketserver
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
if __name__ == "__main__":
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
It seems like you're sending packets using regular userspace sockets. In that case, there's very little chance that the packets are being sent malformed since the FCS is generated physically by the network interface card.
What you're probably seeing is an FCS error due to completely different reasons, which can be safely disregarded.
I'd look for other reasons for why the other device doesn't receive the packet, like firewalls or NAT. Start by using netcat or a similar tool for sending and receiving the UDP packets between the two machines.

Categories

Resources