I would like to make condition from datas from UDP with Python.
here's my code:
import socket
import atexit
UDP_IP = "127.0.0.1"
UDP_PORT = 8002
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
print("listen to port: " + str(UDP_PORT))
while True:
data, addr = sock.recvfrom(1024)
data = data.rsplit(",")
data = data.pop(0)
print(data)
if data=='1':
print("BOOL is TRUE")
"BOOL is true should be printed when data==1, but nothing occurs...
Any clue ? Thanks in advance.
Try replacing this line:
data = data.pop(0)
with this:
data = data.pop(0).strip('\x00')
This will remove the NULLs that are padding the string.
Alternatively, you could look into why the values are being NULL padded and fix it on the server side.
Related
In my python homework, I have to make a server and some clients.
My problem comes from the fixed string size in the packing/unpacking process on both the server and client sides. I want to send messages with two different sized strings.
Here is my simplified code:
client:
import socket
import struct
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(('127.0.0.1', 5555))
str1 = b"A"
msg = (str1, 3)
msg_packed = struct.Struct("1s I").pack(*msg) #the fixed string size is not a problem here
sock.sendall(msg_packed)
reply_packed = sock.recv(1024)
reply = struct.Struct("2s I").unpack(reply_packed) #since the string in the reply can be 'Yes' or 'No' what is 2 and 3 character. I don't know hot make it accept both.
print(reply)
and the Server:
import socket
import select
import struct
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(('0.0.0.0', 5555))
srv.listen()
socks = [srv]
while True:
readable, writeable, err = select.select(socks, [], [], 0.1)
for s in readable:
if s == srv:
client, client_address = srv.accept()
print("New client from: {} address".format(client_address))
socks.append(client)
else:
msg_packed = s.recv(1024)
if msg_packed:
for sock in socks:
if sock == s and sock != srv:
msg = struct.Struct("1s I").unpack(msg_packed)
if (msg[0] == b'A'): #In here the reply message need to be 'Yes' or 'No'
reply = (b'Yes', msg[1] * msg[1])# the struct.Struct("2s I").pack(*reply) will not going to accept this
else:
reply = (b'No', msg[1] + msg[1])
reply_packed = struct.Struct("2s I").pack(*reply)
sock.send(reply_packed)
else:
print("Client disconnected")
socks.remove(s)
s.close()
Is there any way to be able to send both 2 and 3 string lengths? And if yes, how should I change my code?
EDIT: You can just dynamically set the format string of the struct. Here is a simple example:
str1 = b"Yes"
str2 = b"No"
msg_packed1 = struct.Struct("{}s".format(len(str1))).pack(str1)
msg_packed2 = struct.Struct("{}s".format(len(str2))).pack(str2)
In your example it would be
reply_packed = struct.Struct("{}s I".format(len(reply[0]))).pack(*reply)
I got this idea from packing and unpacking variable length array/string using the struct module in python
I tried to send message to server from client with manual input, with 10 limits input. its succesfully work on client side but when i tried to run server it's shows nothing
here's the code from client side
import socket
UDP_IP = "localhost"
UDP_PORT = 50026
print ("Destination IP:", UDP_IP)
print ("Destination port:", UDP_PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for x in range (10):
data = input("Message: ")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print(data)
else :
print("lebih dari 10!!")
s.sendto(data.encode('utf-8'), (UDP_IP, UDP_PORT))
s.close()
here's result and code from server side
import socket
UDP_IP = "localhost"
UDP_PORT = 50026
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((UDP_IP, UDP_PORT))
while True:
data, address = s.recvfrom(1024)
print(data)
print(address)
s.close()
when i run the program, nothing happen. here's the running program
Your main problem is the else statement you added there which is not executing. If want to put a limit of 10 after accepting the input, you are supposed to print the statement after the loop.
This is the client code:
import socket
UDP_IP = "127.0.0.1" # It is the same as localhost.
UDP_PORT = 50026
print ("Destination IP:", UDP_IP)
print ("Destination port:", UDP_PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for x in range (10):
data = input("Message: ")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print(data)
s.sendto(data.encode('utf-8'), (UDP_IP, UDP_PORT))
print("lebih dari 10!!")
s.close()
Edit:
I am not really understanding your problem but as far as I understand you want to show the limit on the server. Thus you can do this, try adding a loop on the server and receive input from the client's address only to avoid receiving extra messages.
Server Code:
import socket
UDP_IP = "127.0.0.1" # It is the same as localhost.
UDP_PORT = 50026
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((UDP_IP, UDP_PORT))
x = 0
while True:
data, address = s.recvfrom(1024)
# This block will make sure that the packets you are receiving are from expected address
# The address[0] returns the ip of the packet's address, address is actually = ('the ip address', port)
if address[0] != '127.0.0.1':
continue
# The logic block ends
print(data)
print(address)
x = x + 1 # This shows that one more message is received.
if x == 10:
break # This breaks out of the loop and then the remaining statements will execute ending the program
print("10 messages are received and now the socket is closing.")
s.close()
print("Socket closed")
I have commented the code so I hope you understand the code
I want to listen port in Python3.
import socket
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
print 'connected:', addr
while True:
data = conn.recv(1024)
if not data:
break
conn.send(data.upper())
conn.close()
The data which I want to listen, looks like:
8,0,0,test,0,2016/07/19,14:40:57.938,2016/07/19,14:40:57.938,,,,,,,,,,,,0
8,0,0,test,0,2016/07/19,14:40:57.965,2016/07/19,14:40:57.965,,,,,,,,,,,,0
3,0,0,test,0,2016/07/19,14:41:04.687,2016/07/19,14:41:04.687,,2475,,,,,,,,,,0
..
that is I need read until '\n'
So I need to change this block, but I dont know how..
data = conn.recv(1024)
if not data:
break
conn.send(data.upper())
I want replace nc:
nc -k -l -p 30003 | python3 script.py
where script.py
while True:
for string in sys.stdin:
Also I need reconnect if something wrong, server must be ready take all data any time, just like nc -k -l -p 30003 | python3 script.py
The main idea is to read until you find \n character in your stream. Of course \n may be beyond 1024 bytes that you are reading thus you need to store everything you read in a buffer. This can be emulated with for example such class:
class SocketLineReader:
def __init__(self, socket):
self.socket = socket
self._buffer = b''
def readline(self):
pre, separator, post = self._buffer.partition(b'\n')
if separator:
self._buffer = post
return pre + separator
while True:
data = self.socket.recv(1024)
if not data:
return None
pre, separator, post = data.partition(b'\n')
if not separator:
self._buffer += data
else:
data = self._buffer + pre + separator
self._buffer = post
return data
And usage:
import socket
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
print('connected:', addr)
reader = SocketLineReader(conn)
while True:
data = reader.readline()
print(data)
if not data:
break
conn.send(data.upper())
conn.close()
If you wish for the server to serve data forever use another while loop:
import socket
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
while True:
conn, addr = sock.accept()
print('connected:', addr)
reader = SocketLineReader(conn)
# The other code goes here
The problem with this approach is that there is no parallelism. Your server won't handle parallel connections. One way to fix that is to send each new connection to a separate thread:
import socket
import threading
def handle(conn):
print('connected:', addr)
reader = SocketLineReader(conn)
# The other code goes here
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
while True:
conn, addr = sock.accept()
threading.Thread(target=handle, args=(conn,)).start()
This should be fine until you hit performance limit. There are ways to improve efficiency (e.g. event loops) but I supposes it's beyond this question.
I found the following code on another post that works pretty good:
UDP_IP = ''
UDP_PORT = 5008
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', UDP_PORT))
while 1:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])
for sock in read_sockets:
#incoming message from remote server
if sock == s:
data = sock.recv(4096)
if not data :
print '\nDisconnected from server'
sys.exit()
else :
#print data
sys.stdout.write(data)
#user entered a message
else :
msg = sys.stdin.readline()
s.send(msg)
The problem I've got is with the for loop since it only runs through it when there is data received. I would really like it to use a while loop and have it occasionally check on if data has been received but I can't figure out how to do this.
Use the timeout parameter in the select statement. If no data is available (indicated by empty lists), you can do whatever other processing is needed in the body of the while loop.
I have the following text file:
ADDRESS1 192.168.124.1
ADDRESS2 192.168.124.2
ADDRESS3 192.168.124.3
And I wrote the following string server in python (strsrv.py) :
#!/usr/bin/env python
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(backlog)
while 1:
global f
client, address = s.accept()
data = client.recv(size)
with open('list.txt', 'r') as my_file:
for f in my_file.readlines():
if(f.find('%s' % data)>-1):
data = f
if f:
client.send(data)
client.send(f)
client.close()
I'm trying to connect to this server sending a string. This string must match one of lines described on text file. Ex: sending 'ADDRESS1' should return 'ADDRESS1 192.168.124.1' from the server, but it doesn't works. Any string sent returns only the last line of the text file. Please could someone point me to the right direction? Thanks :)
How are you testing this? Assuming you open a socket and connect to the host you should see that you are in fact receiving the correct line as well as the last one. Why? Because in the for loop you keep changing the value of f, the last value of f will be the last line in the file, and you send it back after sending data (which at that point is the correct value).
Here's a suggestion for how you might modify your code (assuming you want the full line back and you dont want wildcarding):
#!/usr/bin/env python
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(backlog)
# build dict of addresses first, no need to do this for each message
with open('list.txt', 'r') as my_file:
address_map = dict(line.split() for line in my_file)
while True:
client, address = s.accept()
req_address = client.recv(size)
ip = address_map.get(req_address, 'Not found')
client.send(req_address + ' ' + ip)
client.close()
You can simply test this by doing this while the above is running:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('', 50000))
s.send('ADDRESS2')
s.recv(1024)