我制作了一个基本的http服务器(我正在开发自己的服务器,因为我想在稍后阶段进行低级http分析和操作):
import socket
import threading
import queue
import time
class SocketServer:
"""
Basic Socket Server in python
"""
def __init__(self,host,port,max_theads):
self.host = host
self.port = port
self.server_socket = self.__initSocket()
self.max_theands = max_theads
self.request_queue = queue.Queue()
def __initSocket(self):
return socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def __accept(self):
self.server_socket.listen(5)
while True:
client_socket, client_address = self.server_socket.accept()
self.request_queue.put((client_socket, client_address))
def __handle(self):
while True:
# Dequeue a request and process it
client_socket, address = self.request_queue.get()
# Read HTTP Request
# Log Http Request
# Manipulate Http Request
# Forward or respond
client_socket.sendall(b"""HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body>Hello World</body></html>\r\n""");
;
time.sleep(1)
client_socket.close()
self.request_queue.task_done()
def __initThreads(self):
for _ in range(self.max_theands):
threading.Thread(target=self.__handle, daemon=True).start()
def start(self):
self.server_socket.bind((self.host, self.port))
self.__initThreads()
self.__accept()
我将其启动到一个单独的进程中:
#!/usr/bin/env python3
"""
1. Read settings
2. Bootstrap Manupilator
3. Bootstrap Control Panel
"""
import multiprocessing
from manipulator.http_socket_server import SocketServer
if __name__ == "__main__":
# @todo read settings file
host = "0.0.0.0"
port = 80
max_threads = 5
server = SocketServer(host, port, max_threads)
server_process = multiprocessing.Process(target=server.start)
server_process.start()
# Add other main application code here if needed
server_process.join()
但是curl收到:
curl 10.0.0.2
<html><body>Hello World</body></html>
curl: (56) Recv failure: Connection reset by peer
尽管
__handle
有延迟:
time.sleep(1)
如何优雅地关闭套接字?
一个修复方法是发送内容长度标头:
content = '''<html><body>Hello World</body></html>\r\n'''.encode()
headers = f'''HTTP/1.1 200 OK\r\nContent-Length: {len(content)}\r\nContent-Type: text/html\r\n\r\n'''.encode()
client_socket.sendall(headers + content)
为了解决此问题,您需要先通知客户端 socker 正在关闭:
client_socket.shutdown(socket.SHUT_RDWR)
这将为套接字关闭创建握手,如下所述:https://www.geeksforgeeks.org/tcp-connection-termination/
curl显示错误的原因:
curl: (56) Recv failure: Connection reset by peer
是因为
client_socket.close()
在没有先发送必要的握手的情况下终止了连接。