【问题标题】:Do I need a sleep on receiving data from socket Python从套接字 Python 接收数据时我需要睡眠吗
【发布时间】:2017-04-11 13:55:31
【问题描述】:

我是套接字新手。我用 Python 编写了一个简单的“代理”服务器,它只会从远程服务器捕获数据并将其发送到我的客户端(浏览器)。我想知道:有没有办法在没有 time.sleep 的情况下发送 response_text?当我尝试删除 time.sleep(0.5) 时,我只从远程服务器获取一个数据包,因此“Content-lenght”不等于包的长度,并且出现错误(我正在使用 recv()得到一个大小等于 buffer_size 的缓冲区,所以如果服务器数据需要超过一个 4096 字节的包,我需要在下一个包中捕获它)。通过 time.sleep,我可以从远程服务器获取所有数据包,然后我可以将数据发送到我的浏览器。难道我做错了什么?还是我不够了解?有人可以帮忙吗?

代码:

# coding: utf-8
import socket
import sys
import time
from thread import *

max_conn = 5
buffer_size = 4096


def proxy_server(webserver, port, conn, addr, data):
    try:
        remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        remote_sock.connect((webserver, port))
        remote_sock.send(data)
        response_text = ''
        while True:
            time.sleep(0.5)
            response = remote_sock.recv(buffer_size)
            response_text += response
            if len(response) < buffer_size:
                remote_sock.close()
                break
        conn.sendall(response_text)
        conn.close()
    except socket.error, msg:
        print 'Proccessing error. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
        remote_sock.close()
        conn.close()
        sys.exit()


def conn_string(conn, data, address):
    header = data.split('\r\n')
    method, address, protocol = header[0].split(' ')
    host_key, host_value = header[1].split(': ')
    proxy_server(host_value, 80, conn, address, data)


def start():
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('', 8001))
        sock.listen(max_conn)
        print 'Proxy: on'
    except socket.error, msg:
        print 'Failed creating a socket. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
        sys.exit()

    while True:
        try:
            connection, address = sock.accept()
            data = connection.recv(buffer_size)
            # start_new_thread(conn_string, (connection, data, address))
            conn_string(connection, data, address)
        except KeyboardInterrupt:
            sock.close()
            print "Socket closed"
            sys.exit()

if __name__ == "__main__":
    start()

【问题讨论】:

  • 如果你有一个 content-length 标头,那么使用属性的值循环 socket recv's 直到接收到正确的字节数。

标签: python sockets network-programming


【解决方案1】:

不要使用time.sleep(),它会让你的代理非常变慢,而且效率不高。
您需要将套接字设置为非阻塞模式,并设置超时。
您可以使用 socket.settimeout()
执行此操作 我对你的proxy_server 做了一些修改,现在应该快多了。

def proxy_server(webserver, port, conn, addr, data): 
    try:
        remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        remote_sock.connect((webserver, port))
        remote_sock.send(data)
        remote_sock.settimeout(0.5)
        response_text = ''
        while True:
            try : 
                response = remote_sock.recv(buffer_size)
                if len(response) == 0:
                    break
            except : 
                break
            response_text += response
        conn.sendall(response_text)
    except socket.error, msg:
        if str(msg) != 'timed out' : 
            print 'Proccessing error. Error Code: ' + str(msg[0]) + ', Wiadomość: ' + msg[1]
    remote_sock.close()
    conn.close() 

你的代码的其余部分都很好,但你可能想使用多线程
如果您想同时处理多个客户端。

【讨论】:

  • 对于非阻塞套接字,您不需要使用多线程,您可以使用 select() 或 poll() 来找出需要读取或写入的套接字,并处理它们用一个线程。这样做的好处是避免了所有标准的多线程陷阱(竞争条件、死锁、互斥锁等)
  • 是的,你是对的,假设服务器的超时时间非常低,或者只有几个客户端
  • 根据我的经验,基于 TCP 的服务器永远不需要超时(当然,除非您的服务器实际上正在做一些与时间相关的事情)。相反,一切都可以(并且为了获得最佳性能,应该)纯粹是事件驱动的。
  • 如果您在无限循环中运行sock.accept(),使用非阻塞套接字和 0 超时,很快您将获得 100% 的 GPU 使用率。 OP 必须完全改变他的 start() 函数(你可以发布一个答案)
  • 如果您的事件循环不包含对 select() 或 poll() 的调用,您确实会这样做。在适当的事件驱动的非阻塞套接字设计中,select()(或 poll())调用是代码中唯一阻塞的地方,并且阻塞在那里直到套接字准备好被处理(例如直到它有一个到accept() 的TCP 连接,或者到recv() 的数据,或者send() 可用的缓冲区空间(当然,只有当你想send() 数据时))。然后你处理任何需要处理的事情,然后再次返回阻塞在 select()/poll() 中,并无限重复。
猜你喜欢
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
相关资源
最近更新 更多