Client cannot receive UDP message - python

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.

Related

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

Server unable to sort integer array and send to client

I'm trying to send random size int array from multiple-clients to server which will keep adding the newly received int array to a global array and return accumulated sorted array to client. My client code is able to send and receive int array to/from server. But server is not able to read the int array and sort and send back to client (My server can just read and send back original int array to client, but it's not what I want).
In my server code, commented part is not working. I am very new in python and socket programming.
Client.py
# Import socket module
import socket, pickle
import random
def Main():
# local host IP '127.0.0.1'
host = '127.0.0.1'
# Define the port on which you want to connect
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect to server on local computer
s.connect((host, port))
while True:
# Generate Random array to be sent to server
arr = []
# Generate random size between 10 and 20
# random_size = random.randint(10, 20)
random_size = random.randint(1, 3)
for i in range(0, random_size):
arr.append(random.randint(0, 10))
print('Array = ' + str(arr))
# Serialise the array to byte stream before sending to server
data_stream = pickle.dumps(arr)
#Array byte stream sent to server
s.send(data_stream)
# messaga received from server
data = s.recv(1024)
#deserialise the byte stream into array after receiving from server
data_arr = pickle.loads(data)
# print the received message
#print('Received', repr(data_arr))
print('Received from Server: ', data_arr)
# ask the client whether he wants to continue
ans = input('\nDo you want to continue(y/n) :')
if ans == 'y':
continue
else:
break
# close the connection
s.close()
if __name__ == '__main__':
Main()
Server.py
# import socket programming library
import socket, pickle
# import thread module
from _thread import *
import threading
from sortedcontainers import SortedList
import bisect
#Container to store accumulated int array from multiple clients
sl = SortedList()
# To protect
print_lock = threading.Lock()
# thread fuction
def threaded(c):
while True:
# data received from client
data = c.recv(1024)
# Data from client can't be printed =============== why?
print(data)
if not data:
print('No data received from client - Bye')
# lock released on exit
print_lock.release()
break
c.send(data) # ===> It works but I want to add received int array into global sl before sending back to client
'''
////////////////////// Code in this comment section is not working //////////////////
#Deserialise Byte stream array from client into array list
data_arr = pickle.loads(data)
#Add received int array from client to global sortedList sl in sorted order
for i in data_arr:
bisect.insort(sl, i)
sl.add(i)
print(sl)
#Serialise sorted sl into Byte stream before sending to client
data_stream = pickle.dumps(sl)
# send back sorted integer list to client
c.send(data_stream)
'''
# connection will never be closed, server will run always
#c.close()
def Main():
host = ""
# We can use a port on our specific computer
# But in this case it is 12345 (it can be anything)
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("socket binded to post", port)
# put the socket into listening mode
s.listen(5)
print("socket is listening")
# a forever loop until client wants to exit
while True:
# establish connection with client
c, addr = s.accept()
# lock acquired by client
print_lock.acquire()
print('Connected to :', addr[0], ':', addr[1])
# Start a new thread and return its identifier
start_new_thread(threaded, (c,))
s.close()
if __name__ == '__main__':
Main()
I run it in terminal and I see error
NotImplementedError: use ``sl.add(value)`` instead
but it seems to be incomplete message.
After removing
bisect.insort(sl, i)
it starts working.
Probably there was: use ``sl.add(value)`` instead of ``bisect.insort(sl, i)``

Python - counting times a server receives request from client?

I'm playing around with python lately and trying to learn how to build a python server, using TCP connections.
I have this code that runs a server...
import socket
from threading import *
import datetime
import time
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "localhost"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.sock = socket
self.addr = address
self.start()
def run(self):
while 1:
st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
#cName =
print(self.sock.recv(1024).decode()+' sent # '+ st + ':' , self.sock.recv(1024).decode())
self.sock.send(b'Processing!')
serversocket.listen(5)
print ('server started and listening')
while 1:
clientsocket, address = serversocket.accept()
client(clientsocket, address)
And two of these client.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host ="localhost"
port =8000
cName = 'client 2' # or client 1
s.connect((host,port))
def ts(str):
s.sendall(cName.encode())
s.send('e'.encode())
data = ''
data = s.recv(1024).decode()
print (data)
while 2:
r = input('enter')
ts(s)
s.close ()
I want to know how to allow the server to count and keep track of how many times it recieves a message from both client 1 and client 2.
For example, if server starts at count of 0 (e.g. count = 0). And each time client 1 or client 2 sends back a message or in this case, hits enter, the count will go up (count += 1). If I call for a print(count), the output should be 1.
Thanks?
I think you can create a global variable (say count=0) in your first script (server script) and keep incrementing the value every time you receive the message from a client.
So your run method can become,
def run(self):
global count
while 1:
st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
#cName =
print(self.sock.recv(1024).decode()+' sent # '+ st + ':' , self.sock.recv(1024).decode())
count += 1
self.sock.send(b'Processing!')
If you want the count to be client specific then create a dictionary of counts instead of a single integer and keep incrementing the respective integer on verifying some thing about a client.

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()

Passing from one socket to another

I am trying to write a program that works as an intermedium. (M)
I can only use telnet to connect :
A needs to connect to M, B connects to M.
A sends data to M on a socket, M needs to pass it to B
B sends data to M on another socket
I tried this by starting four threads with a shared list
The problem is it seems it is not writing to the other socket, or even accepting writing.
Does anyone know a better way to implement this and pass it through to another socket
My code :
import sys
import arduinoReadThread
import arduinoWriteThread
import socket
class ControllerClass(object):
'''
classdocs
'''
bolt = 0
socketArray=list()
def __init__(self):
self.readAndParseArgv()
self.createThreads()
def readAndParseArgv(self):
array = sys.argv
print sys.argv
if len(array) != 3:
print "Too few arguments : ./script host:port host:port"
else:
for line in array:
if ":" in line:
splitted = line.split(':')
HOST = splitted[0]
print HOST
PORT = int(splitted[1])
print PORT
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM ) #create an INET, STREAMing socket
s.bind((HOST,PORT)) #bind to that port
print "test"
s.listen(1) #listen for user input and accept 1 connection at a time.
self.socketArray.append(s)
def createThreads(self):
print "Creating Threads"
sharedArray1 = list()
sharedArray2 = list()
s1 = self.socketArray.pop()
s2 = self.socketArray.pop()
sT1 = arduinoWriteThread.writeThread().run(self.bolt,sharedArray1,s2)
sT2 = arduinoReadThread.readThread().run(self.bolt,sharedArray1,s1)
sT3 = arduinoReadThread.readThread().run(self.bolt,sharedArray2,s2)
sT4 = arduinoWriteThread.writeThread().run(self.bolt,sharedArray2,s1)
sT1.start()
sT2.start()
sT3.start()
sT4.start()
x = ControllerClass()
x
Two Threads :
Write Thread :
import threading
class writeThread ( threading.Thread ):
def run ( self,bolt,writeList,sockeToWriteTo ):
s = sockeToWriteTo
while(bolt == 0):
conn, addr = s.accept()
if len(writeList) > 0:
socket.send(writeList.pop(0))
Read Thread
import threading
class readThread ( threading.Thread ):
def run ( self,bolt,writeList,socketToReadFrom ):
s = socketToReadFrom
while(bolt == 0):
conn, addr = s.accept()
f = conn.rcv()
print f
writeList.append(f)
You don't really need threads for this...
When a new connection is accepted, add it to a list. When receiving anything from one of the connection in the list, send to all connections except the one you got the message from.
Use select to see which connections have send data to you.
Edit
Example using select:
# serversocket: One server socket listening on some port, has to be non-blocking
# all_sockets : List containing all connected client sockets
while True:
readset = [serversocket]
readset += all_sockets
# Wait for sockets to be ready, with a 0.1 second timeout
read_ready = select.select(readset, None, None, 0.1)
# If the listening socket can be read, it means it has a new connection
if serversocket in read_ready:
new_connection = serversocket.accept()
new_connection.setblocking(0); # Make socket non-blocking
all_sockets += [new_connection]
read_ready.remove(serversocket) # To not loop over it below
for socket in read_ready:
# Read data from socket
data = socket.recv(2048)
for s in all_sockets:
# Do not send to self
if s != socket:
s.send(data)
Disclaimer I have never really used the Python socket functions, the code above was made from reading the manual pages just now. The code is probably not optimal or very Pythonic either.

Categories