Python使用sockets和sys.stdin进行选择

8
我是一名新手Python程序员,正在尝试创建服务器和客户端。 我仍然希望能够从键盘输入一些内容,以便在服务器上键入“exit”来关闭服务器。我从各个站点获取示例代码以进行套接字编程并得到以下代码。
但是,每当我运行代码时,都会收到以下错误消息:
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.
>>> 

我看到有人提到,在Windows中要解决这个问题,需要删除sys.stdin,因为Windows只接受sockets。我正在尝试在Linux中编写此代码。我已经尝试了各种方法来让它工作,但我已经用尽了所有资源和想法。以下是服务器端的代码:
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()

任何帮助或想法都将不胜感激。谢谢!

你的代码在Linux上对我有效。 - Armin Rigo
这正是我想到的...我发现这段代码与此网站和其他网站引用的sys.stdin和select.select类似。我一定在我的Python中做错了什么。为了更好地说明我正在运行什么,我购买了一个带有重新加载Linux的SD卡的RaspberryPi开发板,并且其中包含Python3。也许我需要配置我的Python或者做些其他的事情才能让sys.stdin和select工作?我正在导入select库... - Leochris Ramos
这是一个相关的讨论:https://dev59.com/4W865IYBdhLWcg3wi_I2 - Illia Bobyr
2个回答

2

虽然我知道您7年前就提出了这个问题,但我也有类似的疑问,所以我想回答您。我仍在工作并修复一个具有相同功能的程序,但我知道的一件事是,作为select.select()参数的列表需要是文件描述符(整数)。

因此,如果您有以下代码块:

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, [], [])

首先,我建议将读取列表更改为不是input。您可能会遇到与input()函数的冲突,这可能会导致混淆的错误。之后,您需要将值设置为文件描述符。因此,第一行应该是:

inputSockets = [s.fileno(), sys.stdin.fileno()]

当检查哪个套接字已准备好时,您应该这样做:

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

0

我在编写Unix域套接字(UDS)接口时遇到了这个问题。服务器套接字ID用于接受传入的客户端连接。这基本上是它所做的所有工作。一旦客户端被接受,读取将使用自己的文件描述符。类似这样的代码可以实现:

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

这个代码块是否会一直等待标准输入的完整行? - user48956
是的,它将读取以换行符终止的整行(通过 sys.stdin.readline()[:-1] 移除),试图与 OP 相似。对于从 stdin 逐个字符读取,我会使用 man:epoll。 - dturvene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接