简体   繁体   English

python-为什么TCP客户端速度变慢然后产生OSError:[Errno 99]无法分配请求的地址

[英]python - Why does TCP client slow down then produce OSError: [Errno 99] Cannot assign requested address

I am writing a server for an event-based simulator and am using asyncio TCP server for this purpose. 我正在为基于事件的模拟器编写服务器,并且为此目的使用了asyncio TCP服务器。

#server.py
import asyncio
import itertools
import json


class Server:
    def __init__(self, loop=None):
        self.loop = loop
        self.pq = asyncio.PriorityQueue()
        self.counter = itertools.count()

    async def __call__(self, reader, writer):
        event = await reader.read(100)
        message = json.loads(event.decode())
        self.pq.put_nowait([next(self.counter), message])
        while self.pq.qsize():
            t = await self.pq.get()
            send_data = json.dumps(t).encode("utf-8")
            writer.write(send_data)
            await writer.drain()

loop = asyncio.get_event_loop()
s = Server(loop)
coro = asyncio.start_server(s, '127.0.0.1', 5000, loop=loop)
server = loop.run_until_complete(coro)

# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

I want a client to send encoded json events to this server quickly. 我希望客户端将编码的json事件快速发送到此服务器。

#client.py
import socket
import json
import datetime

host = "127.0.0.1"
port = 5000

N = 10000
start = datetime.datetime.utcnow()


for i in range(1, N + 1):
    s = socket.create_connection((host, port))
    send_message = {"id": i, "value": i * 3}
    send_json = json.dumps(send_message)
    send_data = send_json.encode("utf-8")
    s.sendall(send_data)
    receive_data = s.recv(1024)
    receive_json = receive_data.decode("utf-8")
    _ = json.loads(receive_json)
    s.close()

stop = datetime.datetime.utcnow()
print("Tasks per second: {}".format(N / (stop - start).total_seconds()))

Problem The client program has varying performance and error generation, despite having no other user programs open. 问题尽管没有打开其他用户程序,该客户端程序仍具有不同的性能和错误生成。

Often, but not always, the first run of client.py runs at about 3,000 tasks per second. 通常,但并非总是如此,第一次运行client.py速度约为每秒3,000个任务。 Occasionally, the first run goes slower (~500-600 tasks per second). 有时,第一次运行会变慢(每秒约500-600个任务)。

Once the performance drops to 500-600 tasks per second, further runs never recover back to 3,000 tasks per second. 一旦性能下降到每秒500-600个任务,进一步的运行就永远不会恢复到每秒3,000个任务。

Eventually, running client.py raises the following exception: 最终,运行client.py会引发以下异常:

Traceback (most recent call last):
  File "aioclient.py", line 12, in <module>
    s = socket.create_connection((host, port))
  File "/home/randm/Libraries/anaconda3/lib/python3.6/socket.py", line 724, in create_connection
    raise err
  File "/home/randm/Libraries/anaconda3/lib/python3.6/socket.py", line 713, in create_connection
    sock.connect(sa)
OSError: [Errno 99] Cannot assign requested address

Question

How should I rewrite client.py (or server.py ) to avoid this? 我应该如何重写client.py (或server.py )以避免这种情况?

Having read https://docs.python.org/3/howto/sockets.html , perhaps a few notes: 阅读了https://docs.python.org/3/howto/sockets.html ,也许有几点注意事项:

  1. The messages will be variable length. 消息将是可变长度的。
  2. I am fine with with either delimiting or sending message length with the messages as opposed to shutting down the connection, which seems to be the underlying source of the problem here. 我可以用消息来界定或发送消息长度,而不是关闭连接,这似乎是这里问题的根本根源。
  3. I'd rather not add an application-layer protocol like HTTP here as I know messages will always be UTF8-encoded JSON. 我宁愿不在此处添加像HTTP这样的应用程序层协议,因为我知道消息将始终是UTF8编码的JSON。

I think using a message delimiter (I've chosen b'\\x1e' ) allows me to have 1 connection for the entire set of messages instead of establishing a new connection for each message. 我认为使用消息定界符(我选择b'\\x1e' )使我可以为整个消息集建立1个连接,而不是为每个消息建立新的连接。 The StreamReader.readuntil method works fine in this case. 在这种情况下, StreamReader.readuntil方法可以正常工作。

# server.py
import asyncio
import itertools
import json


PQ = asyncio.PriorityQueue()
COUNTER = itertools.count()


async def handle_data_provider(reader, writer):
    try:
        while True:
            data = await reader.readuntil(b'\x1e')
            message = json.loads(data[:-1].decode())
            n = next(COUNTER)
            if n % 10000 == 0:
                print(n, PQ.qsize())
            PQ.put_nowait([n, message])
    except asyncio.streams.IncompleteReadError:
        pass

loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_data_provider, '127.0.0.1', 5000, loop=loop)
server = loop.run_until_complete(coro)

# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

And client... 还有客户

# client.py
import socket
import json
import datetime

host = "127.0.0.1"
port = 5000

N = 10000
start = datetime.datetime.utcnow()

s = socket.create_connection((host, port))

for i in range(1, N + 1):
    message = {"id": i, "value": i * 3}
    json_message = json.dumps(message)
    data = json_message.encode("utf-8") + b'\x1e'
    s.sendall(data)

s.close()

stop = datetime.datetime.utcnow()
print("Tasks per second: {}".format(N / (stop - start).total_seconds()))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 OSError:[Errno 99] 无法分配请求的地址:flask、python 和 docker - OSError: [Errno 99] Cannot assign requested address : flask, python and docker OSError:[Errno 99]无法分配请求的地址-py - OSError: [Errno 99] Cannot assign requested address - py Repl.it SMTPLIB OSError: [Errno 99] 无法分配请求的地址 - Repl.it SMTPLIB OSError: [Errno 99] Cannot assign requested address docker-compose up:OSError:[Errno 99]无法分配请求的地址 - docker-compose up: OSError: [Errno 99] Cannot assign requested address PostgreSQL OSError:多个异常:[Errno 111] 连接调用失败('127.0.0.1',5432),[Errno 99] 无法分配请求的地址 - PostgreSQL OSError: Multiple exceptions: [Errno 111] Connect call failed ('127.0.0.1', 5432), [Errno 99] Cannot assign requested address socket.error [Errno 99]无法分配请求的地址 - socket.error[Errno 99] Cannot assign requested address socket.error:[errno 99]无法分配请求的地址:flask和python - socket.error:[errno 99] cannot assign requested address : flask and python socket.error:[errno 99] 无法在 python 中分配请求的地址和命名空间 - socket.error:[errno 99] cannot assign requested address and namespace in python OSError [Errno 99] - python - OSError [Errno 99] - python Flask_oidc 在 Docker 容器中运行时给出“Errno 99 无法分配请求的地址” - Flask_oidc gives `Errno 99 Cannot assign requested address` when run in Docker container
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM