select.select in python need 1 - 3 arguments sequence - python

I keep on receiving this error of 1 - 3 arguments needing to be sequences
import socket # Import socket module
import sys
import select
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
host = "127.0.0.1" # Get local machine name
port = 50001 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
a = []
b = []
s.listen(1) # Now wait for client connection.
c, addr = s.accept() # Establish connection with client.
s.setblocking(0)
ready = select.select(s, s, s, 1) # i believe the error lies in here
while True:
print "reached"
if ready[0]:
print "reached1"
data = mysocket.recv(4096)
print 'Got connection from', addr
c.send('Thank you for connecting \r\n') #all strings have to end with /r/n!!!
print "sent"
c.close() # Close the connection
Error
Select.select arguments 1 - 3 has to be sequences.
I am new to python and hence i am unsure of what the error is. I googled the select code from another post as i wanted my recv socket to be non blocking

select.select takes three lists as arguments, rlist, wlist and xlist:
rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition” (see the manual page for what your system considers such a condition)
You're not passing lists but single sockets.
Try this:
ready = select.select([s], [s], [s], 1)
The return value will, again, be a tuple of three lists, the first containig sockets ready for reading, the second sockets ready for writing and the third sockets in 'exceptional condition'.
Note also that in your while loop you never update ready, so you will always use the same lists of sockets. Also, you should have a break somewhere, otherwise you'll end up calling c.send in an endless loop.

Related

Python Socket takes forever only on first iteration of loop?

The title says it all. The loop takes forever for the first port and then the rest of them only take one second.
import socket
target = "192.168.0.104"
try:
for port in range(52,85):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(1)
result=s.connect_ex((target,port))
if result == 0:
print("Port {} is open".format(port))
else:
print("Port {} is closed".format(port))
s.close()
# break
except KeyboardInterrupt:
print ('you stopp it manually')
except socket.gaierror:
print ("Cant resolve host name")
for port in range(52,85):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(1)
...
You first create the socket, then call socket.setdefaulttimeout. But from the documentation:
socket.setdefaulttimeout(timeout) Set the default timeout in seconds
(float) for new socket objects. When the socket module is first
imported, the default is None. See settimeout() for possible values
and their respective meanings.
Thus, the first socket you create is not affected from the default timeout, since you set it after the socket creation. That's why it takes that long.
Apart from that it does not make much sense to call socket.setdefaulttimeout again and again with the same value. Since the new setting will affect all newly created sockets it is sufficient to call it once before any socket gets created, i.e.
socket.setdefaulttimeout(1)
for port in range(52,85):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
...

Python socket loop does not break

I created socket for two PC, one is Raspberry Pi and the other one is my laptop. I just connected two then I send string to test the connection. If I send a character "q" from the RPi, my PC should break out of the loop and close the connection but it does not. The part print("Listening") is still running. Why? See code below.
import socket
import time
# IP address of this PC.
TCP_IP = '192.168.137.1'
# Port.
TCP_PORT = 5005
# Size of buffer.
BUFFER_SIZE = 1024
# Create a socket, connect and listen to it.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print('Connection address:', addr)
while 1:
print("Listening")
data = conn.recv(BUFFER_SIZE)
data = data.decode()
if data=='q':
break
if data:
print ("Received data:", data)
# Echo back.
conn.send(data.encode())
time.sleep(1)
print("It breaks.")
conn.close()
s.close()
TCP is a stream oriented protocol. So data transmitted is a stream not a sequence of messages. So when you expect data to be q it actually is some_data_sent_before_q_and_finally_q.
The simplest way to repair the code is to use if data.endswith('q') instead of if data=='q'. May work and may not depending on how you actually use the connection. For example, this approach may fail with some_data_sent_before_q pretty long pause more_data_and_q and with some_data_sent_before_q_and_finally_q_plus_something_else_why_not.
Little bit more advanced way to solve the problem is to divide the stream into messages with separators - message_1<separator>message_2<separator>q<separator>. This method will allow you to treat every message separately.

How to call a function after some interval in python server?

I've a python socket server which listens to HTTP requests. It returns ip address and it's port after randomly choosing from a list of ip adresses. This result is generated by another file which fetches it from a database. The database is continuously updated. I want the list to be updated after every 10 requests or after 100 seconds any one of them will work. The below code doesn't work for me. The connection gets reset after every five requests. I printed the count and it increased to 10 after every 5 requests. Can anyone tell me what I'm missing here ?
result=get_ip() # Get a list of dictionary by calling get_ip() function
HOST, PORT = '127.0.0.1', 8890
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(10)
print 'Serving HTTP on port %s ...' % PORT
count = 0
while True:
if count % 10 == 0:
result=get_ip()
count +=1
client_connection, client_address = listen_socket.accept()
rand_ip = random.choice(result)
ip = rand_ip["ip"]
port = rand_ip["port"]
client_connection.sendall(ip+":"+port)
client_connection.close()
The problem comes from the close. It is dangerous to close a socket immediately after writing something into it. You should first shutdown the socket to make the peer to have a 0 read indicating a proper and of stream
So you script should end with:
client_connection.sendall(ip+":"+port)
try:
client_connection.shutdown(socket.SHUT_WR) # signal end of strem
while True: # wait for the client to close or shutdown his side
q = client_connection.recv(1024)
if len(q) == 0:
break
finally:
client_connection.close() # close the socket only after the client has close its side

Python select with sockets and sys.stdin

I'm new to Python programming and I'm trying to create a server and a client. I still want to be able to type something from the keyboard so i can close the server from the server by typing 'exit'. I've taken samples codes from various sites to get to where I'm at in socket programming and this code.
However, whenever I run the code I get the following error message:
The host name of this machine is 127.0.0.1
The IP address of the host is 127.0.0.1
Server now awaiting client connection on port 2836
im right before the select
Traceback (most recent call last):
File "/root/Server_2.py", line 42, in <module>
inputready, outputready, exceptready = select.select(input, [], [])
TypeError: argument must be an int, or have a fileno() method.
>>>
I was reading around that to get passed this (in Windows) is to remove the sys.stdin because Windows only accepts sockets. I'm trying to write this code in Linux. I've tried all sorts of things to try to get it to work and I'm all out of resources and ideas to try. Below is the server code:
import socket #import socket module
import select
import sys
host = "127.0.0.1"
print ("The host name of this machine is " + host)
hostIP = socket.gethostbyname(host) # get host IP address
print ("The IP address of the host is %s" % (hostIP))
port = 2836 # Reserve the port for the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((hostIP, port)) # This server to a port
s.listen(4) # Now wait for client connection
print("Server now awaiting client connection on port %s" % (port))
#WINDOWS ONLY ACCEPTS SOCKETS FOR SELECT(), no standard in
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
print("i'm here na")
# check who made a response
for x in inputready:
if x == s:
print(s)
#handle the server socket
client, address = s.accept()
print("connection comming in")
input.append(client)
elif x == sys.stdin:
# handle standard input
stuff = sys.stdin.readline()
if stuff == "exit":
running = 0
else:
print("you typed %s" % (stuff))
else:
#handle all other sockets
data = x.recv(1024)
print("i received " + data)
if data:
if data == "exit":
x.close()
input.remove(x)
running = 0
else:
x.send(data)
print("I am sending %s" % (data))
else:
x.close()
input.remove(x)
s.close()
Any help or ideas would be greatly appreciated. Thanks!!
Well I know you asked this 7 years ago, but I had similar questions so I would figure I answer you. I'm still working and bugfixing a program that has the same functionality, but one thing I do know is that the lists that are the arguments in select.select() need to be file descriptors (ints).
So if you have this block
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
The first thing I'd say is change your read list to not be input. You'll likely get some clashing with the input() function, which may cause confusing bugs. After that, you want the values to be file descriptors. So that first line should be
inputSockets = [s.fileno(), sys.stdin.fileno()]
Then when checking which socket is ready to ready, you would want to do it like this
for x in inputready:
if x == s.fileno():
# Read from your s socket
elif x == sys.stdin().fileno():
# Read from stdin
else:
'''
Here you would want to read from any other sockets you have.
The only problem is your inputSockets array has ints, not socket
objects. What I did was store an array of actual socket objects
alongside the array of file descriptors. Then I looped through the
list of sockets and found which socket's .fileno() matched x. You could
probably be clever and use a dict() with the filenos as key and socket as
value
'''
I just came across this while writing a unix domain socket (UDS) interface. The server socket id is used to accept incoming client connections. That is pretty much all it does. Once the client is accepted, reading uses its own file descriptor. Something like this works:
conn = None
inputReady, Null, Null = select.select(inputSockets, [], [])
for x in inputReady:
if x == s.fileno():
# accept incoming connect and add to poll list
conn, addr = s.accept()
inputReady.append(conn.fileno())
elif x = sys.stdin.fileno():
# read whole line and remove newline
cmd = sys.stdin.readline()[:-1]
...
elif conn and x == conn.fileno():
data = conn.recv(msglen)
if data:
....
else:
# connection has ended, remove from poll list and close
if conn.fileno() in inputReady:
inputReady.remove(conn.fileno())
conn.close()

How do I abort a socket.recv() from another thread in Python

I have a main thread that waits for connection. It spawns client threads that will echo the response from the client (telnet in this case). But say that I want to close down all sockets and all threads after some time, like after 1 connection.
How would I do it? If I do clientSocket.close() from the main thread, it won't stop doing the recv. It will only stop if I first send something through telnet, then it will fail doing further sends and recvs.
My code looks like this:
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocket):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
# It will hang here, even if I do close on the socket
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
time.sleep(1)
# This won't make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
I know this is an old thread and that Samuel probably fixed his issue a long time ago. However, I had the same problem and came across this post while google'ing. Found a solution and think it is worthwhile to add.
You can use the shutdown method on the socket class. It can prevent further sends, receives or both.
socket.shutdown(socket.SHUT_WR)
The above prevents future sends, as an example.
See Python docs for more info.
I don't know if it's possible to do what you're asking, but it shouldn't be necessary. Just don't read from the socket if there is nothing to read; use select.select to check the socket for data.
change:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
to something more like this:
r, _, _ = select.select([self.clientSocket], [], [])
if r:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
EDIT: If you want to guard against the possibility that the socket has been closed, catch socket.error.
do_read = False
try:
r, _, _ = select.select([self.clientSocket], [], [])
do_read = bool(r)
except socket.error:
pass
if do_read:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
I found a solution using timeouts. That will interrupt the recv (actually before the timeout has expired which is nice):
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocke):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except socket.timeout:
# If it was a timeout, we want to continue with recv
continue
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
clientSocket.settimeout(1)
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
# Close it down immediatly
clientSocket.close()
I must apologize for the comments below. The earlier comment by #Matt Anderson works. I had made a mistake when trying it out which led to my post below.
Using timeout is not a very good solution. It may seem that waking up for an instant and then going back to sleep is no big deal, but I have seen it greatly affect the performance of an application. You have an operation that for the most part wants to block until data is available and thus sleep forever. However, if you want to abort for some reason, like shutting down your application, then the trick is how to get out. For sockets, you can use select and listen on two sockets. Your primary one, and a special shutdown one. Creating the shutdown one though is a bit of a pain. You have to create it. You have to get the listening socket to accept it. You have to keep track of both ends of this pipe. I have the same issue with the Synchronized Queue class. There however, you can at least insert a dummy object into the queue to wake up the get(). This requires that the dummy object not look like your normal data though. I sometimes wish Python had something like the Windows API WaitForMultipleObjects.

Categories