Python Socket Using Select To Check For Data - python

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.

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'

How to make client and server send and accept different message lengths in python

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

Cannot read message from client : UDP python 3

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

condition from UDP data doens't work in PYTHON

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.

Check if data available in sockets in python

I want a functionality to check if data is waiting in the socket to be read before reading it. Something like this would be helpful:
if (data available) then read data
else wait in blocking mode till data becomes available
How can I achieve this in Python
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)

Categories