Last active
March 22, 2023 10:34
-
-
Save remittor/f2c89f50ff259e6e704fe246ee6c3dd5 to your computer and use it in GitHub Desktop.
pl_test.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import io | |
import time | |
import datetime | |
import socket | |
import asyncore | |
import struct | |
import optparse | |
parser = optparse.OptionParser("usage: %prog [options]", add_help_option=False) | |
parser.add_option("-h", "--host", dest="host", default='127.0.0.1', type="string") | |
parser.add_option("-p", "--port", dest="port", default=5000, type="int") | |
parser.add_option("-u", "--url", dest="url", default="/", type="string") | |
parser.add_option("-@", "--shorttest", dest="shorttest", action="store_true", default=False) | |
parser.add_option("-#", "--chunknum", dest="chunknum", default=3, type="int") | |
(opt, args) = parser.parse_args() | |
def get_request(path = r'/', host = '127.0.0.1', port = 5000): | |
req = f'GET {path}' + r' HTTP/1.1' + '\r\n' | |
req += f'Host: {host}:{port}\r\n' | |
req += r'User-Agent: curl/7.66.0' + '\r\n' | |
#req += r'Accept: */*' + '\r\n' | |
req += r'Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7' + '\r\n' | |
req += r'Connection: keep-alive' + '\r\n' | |
req += '\r\n' | |
return req.encode('utf8') | |
payload_base = get_request(path = opt.url, host = opt.host, port = opt.port) | |
payload_size = len(payload_base) | |
def create_sock(timeout = 0.1): | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.settimeout(timeout) | |
sock.connect((opt.host, opt.port)) | |
return sock | |
print(f'base payload size = {len(payload_base)} (0x%X)' % len(payload_base)) | |
payload = payload_base * opt.chunknum | |
chunk_size = payload_size * (opt.chunknum - 1) + payload_size // 2 | |
resp = b'' | |
sock = create_sock(1) | |
sock.sendall(payload[0:chunk_size]) | |
time.sleep(0.1) | |
try: | |
resp += sock.recv(4096) | |
except socket.timeout: | |
pass | |
print(f'recv preload size = {len(resp)}') | |
sock.sendall(payload[chunk_size: ]) | |
time.sleep(0.1) | |
try: | |
resp += sock.recv(4096) | |
except socket.timeout: | |
print(resp.decode('utf-8')) | |
raise | |
print('total resp size =', len(resp)) | |
print(resp) | |
print('====== response ========') | |
print(resp.decode('utf-8')) | |
print('========================') | |
sock.close() | |
g_resp_size = len(resp) // opt.chunknum | |
print(f'Test 0 completed! {opt.chunknum=}') | |
if opt.shorttest: | |
sys.exit(0) | |
# ================================================================= | |
start_time = datetime.datetime.now() | |
test1_limit = start_time + datetime.timedelta(seconds = 1) | |
test2_limit = test1_limit + datetime.timedelta(minutes = 10) | |
totalrecv = 0 | |
sock = create_sock() | |
while True: | |
if datetime.datetime.now() >= test1_limit: | |
break | |
sock.sendall(payload_base) | |
try: | |
resp = sock.recv(4096) | |
totalrecv += len(resp) | |
except socket.timeout: | |
pass | |
print(f'Test 1 completed! {totalrecv=}') | |
sock.close() | |
# ================================================================= | |
print(f'Run test 2 ...') | |
req_num = 10*1000*1000 | |
#req_num = 1000 | |
payload_huge = payload_base * req_num | |
print(f'payload_huge = {len(payload_huge)} bytes') | |
g_expected_recv = g_resp_size * req_num | |
class HttpClient(asyncore.dispatcher): | |
def __init__(self, buffer): | |
asyncore.dispatcher.__init__(self) | |
self.create_socket() | |
self.connect( (opt.host, opt.port) ) | |
self.buffer = buffer | |
self.totalsent = 0 | |
self.totalrecv = 0 | |
self.lastresp = b'' | |
self.show_time = datetime.datetime.now() | |
def handle_connect(self): | |
self.show_time = datetime.datetime.now() | |
def handle_close(self): | |
print(f'totalrecv = {self.totalrecv}') | |
print('Close HTTP client') | |
self.close() | |
def handle_read(self): | |
resp = self.recv(65*1024) | |
self.totalrecv += len(resp) | |
if len(resp) == 0: | |
raise "Remote peer disconnected." | |
self.lastresp = resp | |
#print('>>>', resp) | |
if resp.find(b'HTTP/1.1 4') >= 0 or resp.find(b'HTTP/1.1 5') >= 0: | |
raise '==== BAD Request =====' | |
if self.show_time <= datetime.datetime.now(): | |
self.show_time = datetime.datetime.now() + datetime.timedelta(seconds = 2) | |
print(f'totalrecv = {self.totalrecv}') | |
if self.totalrecv >= g_expected_recv - g_resp_size * 4: | |
self.handle_close() | |
def writable(self): | |
return True if (self.totalsent < len(self.buffer)) else False | |
def handle_write(self): | |
sent = self.send(self.buffer[self.totalsent:]) | |
self.totalsent += sent | |
if sent > 0: | |
print(f'sent = {sent} totalsent = {self.totalsent}') | |
#if self.totalsent >= len(self.buffer): | |
# self.handle_close() | |
client = HttpClient(payload_huge) | |
asyncore.loop() | |
#asyncore.loop(use_poll = True) | |
print("==== Test Finish =====") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment