43

I am trying to write an echoing client/server socket. I have written the server so that 30% of the packets are lost. I programmed my client to timeout after one second since the packet could be lost. However, whenever I run my client socket, my output is 100% REQUEST TIMED OUT. I'm assuming I'm getting this output because my server is never receiving the message. I've looked over my code multiple times and cannot figure out why I am constantly getting this output.

Server:

# We will need the following module to generate randomized lost packets
import random
from socket import *

# Create a UDP socket
# Notice the use of SOCK_DGRAM for UDP packets
serverSocket = socket(AF_INET, SOCK_DGRAM)

# Assign IP address and port number to socket
serverSocket.bind(('', 12000))

while True:
    # Generate random number in the range of 0 to 10
    rand = random.randint(0, 10)
    
    # Receive the client packet along with the address it is coming from
    message, address = serverSocket.recvfrom(1024)
    
    # Capitalize the message from the client
    message = message.upper()
    
    # If rand is less is than 4, we consider the packet lost and do notrespond
    if rand < 4:
        continue
    
    # Otherwise, the server responds
    serverSocket.sendto(message, address) 

Client:

import time
from socket import *

pings = 1

#Send ping 10 times 
while pings < 11:  
    
    #Create a UDP socket
    clientSocket = socket(AF_INET, SOCK_DGRAM)

    #Set a timeout value of 1 second
    clientSocket.settimeout(1)

    #Ping to server
    message = 'test'

    addr = ("127.0.0.1", 12000)
    
    #Send ping
    start = time.time()
    clientSocket.sendto(message, addr)

    #If data is received back from server, print 
    try:
        data, server = clientSocket.recvfrom(1024)
        end = time.time()
        elapsed = end - start
        print data + " " + pings + " "+ elapsed        

    #If data is not received back from server, print it has timed out  
    except timeout:
        print 'REQUEST TIMED OUT'

    pings = pings - 1
3
  • 5
    If you came here from a Google search for how to implement UDP sockets in Python and wonder why some requests are failing, it's intentional. Read the post carefully. Commented Apr 17, 2021 at 1:27
  • If you're using an AWS AMI, make sure you are using the PUBLIC ip not the PRIVATE ip. Commented Sep 4, 2021 at 7:43
  • 1
    A minor point: for the sake of readability, avoid import *. Either list the imported modules or functions explicitly or just import the base module and use the dot notation throughout your code; this way, future readers (including yourself!) will quickly be able to identify where things are coming from. @bsa provides other good suggestions to improve the quality of your code. Commented Mar 20, 2022 at 4:36

2 Answers 2

65

I tested your code, and it works as expected on my machine. Your issue might not be your code. It could be a firewall or something else blocking all the packets on the loopback interface (127.0.0.1). Depending on your operating system, try testing with a packet monitor like Wireshark.

Also, here are a few suggestions on how to improve your code to be more Pythonic:

Server

import random
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('', 12000))

while True:
    rand = random.randint(0, 10)
    message, address = server_socket.recvfrom(1024)
    message = message.upper()
    if rand >= 4:
        server_socket.sendto(message, address)

Client

import time
import socket

for pings in range(10):
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client_socket.settimeout(1.0)
    message = b'test'
    addr = ("127.0.0.1", 12000)

    start = time.time()
    client_socket.sendto(message, addr)
    try:
        data, server = client_socket.recvfrom(1024)
        end = time.time()
        elapsed = end - start
        print(f'{data} {pings} {elapsed}')
    except socket.timeout:
        print('REQUEST TIMED OUT')
Sign up to request clarification or add additional context in comments.

7 Comments

Okay, that would explain things. I've stared at this things for hours and could not figure it out. Thank you very much, and thank you for the tips
In line clientSocket.sendto(message, addr) didn't you get error of TypeError: a bytes-like object is required, not 'str'
My guess would be that I used Python 2, you might be using Python 3?
"more pythonic" you literally just removed the excess newlines and comments, and changed one while-loop into a for loop
Also deleted a continue, and used the string format operator instead of string concatenation :) What else would you change?
|
7

Here is an alternative with asyncio.

import asyncio
import random

class EchoServerProtocol:
    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr):
        message = data.decode()
        print('Received %r from %s' % (message, addr))
        rand = random.randint(0, 10)
        if rand >= 4:
            print('Send %r to %s' % (message, addr))
            self.transport.sendto(data, addr)
        else:
            print('Send %r to %s' % (message, addr))
            self.transport.sendto(data, addr)


loop = asyncio.get_event_loop()
print("Starting UDP server")

# One protocol instance will be created to serve all client requests
listen = loop.create_datagram_endpoint(
    EchoServerProtocol, local_addr=('127.0.0.1', 12000))
transport, protocol = loop.run_until_complete(listen)

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

transport.close()
loop.close()

2 Comments

Could you please add a few lines to describe your code block. E.g. Why would anyone do it this way? Pros/Cons? Thanks for the example!
if rand >= 4: is same as in else block , so why you need to use if else at first place ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.