Python select with sockets and sys.stdin
Asked Answered
E

2

9

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!!

Extranuclear answered 8/2, 2013 at 5:41 Comment(3)
Your code works for me on Linux.Fiducial
That's what I figured...I see this code similar to this site and other sites reference the sys.stdin and select.select. I must be doing something wrong with my Python. To give more reference on what I'm running, I bought a RaspberryPi development board with linux reloaded in the SD card and it contains Python3. Is it possible that maybe I need to configure my Python or something to get sys.stdin and select to work? I am importing the select library....Extranuclear
This is a related discussion: #3763381Dahle
S
4

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
        '''
Sitarski answered 4/12, 2020 at 15:53 Comment(0)
A
1

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()
Aquiculture answered 9/3, 2022 at 17:55 Comment(2)
Doesn't this block receiving s until a complete line of stdin?Lilllie
Yes, it will read an entire line terminated by newline (which is removed by sys.stdin.readline()[:-1] trying to be similar to OP. For char-by-char read from stdin, I would use man:epollAquiculture

© 2022 - 2024 — McMap. All rights reserved.