【发布时间】:2020-07-10 21:51:40
【问题描述】:
我正在尝试让 Unity 和 Python 程序通过 HTTP 进行通信。 Unity 服务器通过 HTTPCient 发送 HTTP 请求,Python 程序通过 HTTPServer 处理该请求。我遇到的问题是每个请求似乎都将一个套接字发送到 TIME_WAIT。通信大约每秒发生 20 次,最终没有更多的套接字,程序停止运行。我的理解是这个问题是由于每个请求都使用了一个新的套接字而没有正确关闭它,下面的 Wireshark 捕获似乎支持它(最后只有一个 FIN-ACK,而不是我理解的 TCP 要求的 2 个)。
我正在尝试使用更少的套接字,或者尽快释放套接字以便再次使用它们。我尝试了多种方法来缓解这个问题,包括socket.SO_REUSEADDR、连接池和保持连接。我怀疑我没有正确实施其中的一个(或全部),但我不确定如何确认。下面的代码是我尝试实现下面的代码 - 不幸的是,python 方面的文档感觉有点稀疏。
void Start() {
HttpClient requester = new HttpClient();
requester.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
requester.DefaultRequestHeaders.Add("Keep-Alive", "5000");
waitForClientResult(requester);
}
private async Task waitForClientResult(HttpClient requester) {
HttpResponseMessage response = await requester.GetAsync("http://127.0.0.1:5018");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
PythonServerReturnData data = JsonUtility.FromJson<PythonServerReturnData>(responseBody);
doSomeStuffWithTheData(data);
waitForClientResult(requester);
}
agent = UnityAgentHTTP()
class UnityAgentHTTP:
def __init__(self):
self.recievedData = None
self.replyData = "ThisDataUpdatedElsewhere".encode('utf-8')
self.exit = False
self.sendThread = threading.Thread(target=self.sendOutput, name='sendThread', daemon = True)
self.sendThread.start()
def sendOutput(self):
handler = partial(UnityHTTPServer, self)
self.httpd = MyHTTPServer(('127.0.0.1', 5018), handler)
self.httpd.serve_forever()
def cleanup(self):
print("cleaning up")
self.exit = True
self.httpd.shutdown()
self.httpd.socket.close()
self.httpd.server_close()
class MyHTTPServer(HTTPServer):
allow_reuse_address = True
def server_bind(self):
HTTPServer.server_bind(self)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# self.socket.bind(self.server_address)
class UnityHTTPServer(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
def __init__(self, unityAgentHTTP: UnityAgentHTTP, *args, **kwargs):
self.unityAgentHTTP = unityAgentHTTP
super().__init__(*args, **kwargs)
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "application/json")
# self.send_header("Connection", "Keep-Alive")
# self.send_header("keep-alive", "timeout=5, max=30")
self.send_header("Content-Length", len(self.unityAgentHTTP.replyData) + 20) # TODO horrible hack bc i can't figure out how to count bytes objects properly
self.end_headers()
def do_GET(self):
self.do_HEAD()
self.wfile.write(self.unityAgentHTTP.replyData)
self.close_connection = True
【问题讨论】:
-
不确定这是否能解决您的所有问题,但是否可以像不等待客户端上的异步任务一样简单?我听说如果您在不等待它们的情况下“触发并忘记”异步 void 可能会出现问题,尤其是在错误处理方面。但是,不确定其中有多少延伸到任务。您可以尝试
waitForClientResult(requester).GetAwaiter().GetResult()之类的方法,看看是否有帮助。 -
@joshua.software.dev 感谢您的建议!我试着等待电话,但似乎没有帮助。如果不冻结程序,我就无法让
waitForClientResult(requester).GetAwaiter().GetResult()工作。
标签: python c# unity3d networking