开发者社区 问答 正文

select()方法的循环

这是一个消息应用程序,可以发送消息从一个客户端到另一个客户端通过服务器,我调试这段代码,它是循环的read_socket, _, _ = select.select(self。输入,[],[],1) 用于读取read_socket: for ever。

import socket
import select
import errno
import sys

class client_app():

    def __init__(self):

        self.HEADER_LENGTH = 10
        self.IP = "127.0.0.1"
        self.PORT = 1234
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect((self.IP, self.PORT))
        self.client_socket.setblocking(False)
        self.inputs = [sys.stdin, self.client_socket]

    def client(self, send_message):
        while True:
            read_socket, _ , _ = select.select(self.inputs, [], [], 1)
            for read in read_socket:
                if read is client_socket:
                    try:
                        while True:
                            message_header = client_socket.recv(HEADER_LENGTH)
                            message_length = int(message_header.decode('utf-8').strip())
                            message = client_socket.recv(message_length).decode('utf-8')
                            print(message)
                    except IOError as e:
                        if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                            sys.exit()
                        continue
                    except Exception as e:
                        sys.exit()
                else:
                    try:
                        message = send_message
                        if message:
                            message = message.encode('utf-8')
                            message_length = int(message_header.decode('utf-8').strip())
                            client_socket.send(message_header + message)
                    except IOError as e:
                        if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                            sys.exit()
                        continue
                    except Exception as e:
                        sys.exit()

if __name__=='__main__':
    cli = client_app()
    cli.client('ahmad')
    cli.client('jan')```

问题来源StackOverflow 地址:/questions/59379805/looping-on-select-select-method-for-infinite

展开
收起
kun坤 2019-12-29 21:40:32 436 分享 版权
阿里云 AI 助理回答

这段代码展示了一个简单的客户端应用程序,它使用Python的socketselect模块来实现实时地从服务器接收消息以及向服务器发送消息。下面是对代码中关键部分的解释以及可能存在的问题和改进建议:

  1. 初始化与连接:客户端通过socket.socket()创建一个套接字,并使用connect()方法连接到指定的IP地址和端口。这里设置为本地环回地址(127.0.0.1)和端口1234

  2. 非阻塞模式:通过setblocking(False)将套接字设置为非阻塞模式,这意味着当没有数据可读时,recv()调用不会阻塞,而是立即返回一个错误。

  3. 使用select监控输入select.select()函数用于同时监控多个IO通道(如文件描述符)。在这个例子中,它监控标准输入(用户输入)和客户端套接字是否有数据可读。第四个参数1是超时时间,意味着如果在1秒内没有I/O事件发生,select()会返回。

  4. 消息处理循环

    • 对于来自服务器的消息,代码尝试不断读取消息头以确定消息长度,然后根据长度读取消息内容并打印。但是,这里存在一个问题:message_header = client_socket.recv(HEADER_LENGTH)应该放在外层循环里,因为它只需要在开始读取新消息时获取一次。
    • 发送消息的部分也有误,message_length = int(message_header.decode('utf-8').strip())这行应该是在准备发送消息之前计算消息的实际长度,而不是在这里重复使用接收时的逻辑。此外,发送消息时应确保正确构造了消息头和消息体。
  5. 错误处理:通过捕获IOError和更通用的Exception来处理潜在的错误,比如网络中断或编码解码错误。

改进建议

  • 修正消息接收逻辑:将消息头的接收移到循环外面,确保每次循环只处理一条完整消息。
  • 修复发送消息逻辑:正确计算待发送消息的长度,并在发送前构造消息头。
  • 避免重复发送相同消息:当前实现中,client('ahmad')client('jan')连续调用,但实际应用中通常不需要这样。可以考虑在主循环中等待用户输入不同的消息再发送。
  • 资源管理:考虑在程序结束时关闭套接字,使用try...finally或上下文管理器(with语句)确保资源被妥善释放。

下面是修改后的发送消息部分示例代码:

def client(self, send_message):
    message = send_message.encode('utf-8')
    message_header = f"{len(message):<{self.HEADER_LENGTH}}".encode('utf-8')
    
    while True:
        read_socket, _, _ = select.select(self.inputs, [], [], 1)
        for read in read_socket:
            if read is self.client_socket:
                try:
                    message_header = self.client_socket.recv(self.HEADER_LENGTH)
                    if not len(message_header):
                        print("Connection closed by the server.")
                        sys.exit()
                    message_length = int(message_header.decode('utf-8').strip())
                    message = self.client_socket.recv(message_length).decode('utf-8')
                    print(message)
                except IOError as e:
                    if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                        sys.exit()
                    continue
                except Exception as e:
                    sys.exit()
            else:
                try:
                    self.client_socket.send(message_header + message)
                    # 可能需要清除或更新send_message变量,取决于你的需求
                except IOError as e:
                    if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                        sys.exit()
                    continue
                except Exception as e:
                    sys.exit()

请注意,上述修改仅针对你提供的代码片段进行,具体应用中还需根据实际情况调整。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答
问答地址: