Python中的tcp套接字客户端如何与uwsgi对话?
我的架构是
tcp 套接字客户端 -> nginx -> uwsgi
tcp 套接字客户端 -> uwsgi
通过与套接字对话
uwsgi
协议。该协议在 uWSGI 文档中进行了描述。
Python 文档包含 这里有一个关于 TCP 和 Unix 套接字的不错的教程。
编辑: 有关工作示例,请参阅 https://github.com/akx/uwsgi-socket-example。
不清楚你到底想知道什么,所以让我从以下问题开始:
客户如何与
交谈?uwsgi
$ python -m venv venv
$ venv/bin/pip install uwsgi-tools
$ venv/bin/uwsgi_curl /var/run/uwsgi-socket example.com
uwsgi-tools
软件包 (GitHub),并运行 uwsgi
客户端 (uwsgi_curl
),将其传递给 uwsgi
服务器套接字 (/var/run/uwsgi-socket
) 的路径)和 URL (example.com
)。)
让我们看一下客户端和服务器端到底发送了什么内容。为此,让我们将
socat
放在它们之间:
$ socat -r /tmp/request -R /tmp/response \
UNIX-LISTEN:/tmp/proxy UNIX-CONNECT:/var/run/uwsgi-socket
(此处
socat
将 /tmp/proxy
处的 Unix 域套接字与 uwsgi
处 /var/run/uwsgi-socket
处的套接字连接起来。请求存储在 /tmp/request
中,响应存储在 /tmp/response
中。)
并提出要求:
$ python -m venv /tmp/venv
$ /tmp/venv/bin/pip install uwsgi-tools
$ /tmp/venv/bin/uwsgi_curl /tmp/proxy example.com
$ xxd /tmp/request
00000000: 0094 0000 0f00 5345 5256 4552 5f50 524f ......SERVER_PRO
00000010: 544f 434f 4c08 0048 5454 502f 312e 3109 TOCOL..HTTP/1.1.
00000020: 0050 4154 485f 494e 464f 0100 2f0e 0052 .PATH_INFO../..R
00000030: 4551 5545 5354 5f4d 4554 484f 4403 0047 EQUEST_METHOD..G
00000040: 4554 0b00 5245 5155 4553 545f 5552 4901 ET..REQUEST_URI.
00000050: 002f 0c00 5155 4552 595f 5354 5249 4e47 ./..QUERY_STRING
00000060: 0000 0900 4854 5450 5f48 4f53 540d 0065 ....HTTP_HOST..e
00000070: 7878 7861 6d70 6c65 2e63 6f6d 0b00 5345 xxxample.com..SE
00000080: 5256 4552 5f4e 414d 450d 0065 7878 7861 RVER_NAME..exxxa
00000090: 6d70 6c65 2e63 6f6d 0a mple.com.
$ xxd /tmp/response
00000000: 4854 5450 2f31 2e31 2032 3030 204f 4b0d HTTP/1.1 200 OK.
00000010: 0a43 6f6e 7465 6e74 2d54 7970 653a 2074 .Content-Type: t
...
根据协议规范,首先是头部:
struct uwsgi_packet_header {
uint8_t modifier1;
uint16_t datasize;
uint8_t modifier2;
};
在我们的例子中
modifier1 == 0
,datasize == 0x94
(小端),modifier2 == 0
。就这样:
标准 WSGI 请求后跟 HTTP 请求正文
然后是变量:
struct uwsgi_var {
uint16_t key_size;
uint8_t key[key_size];
uint16_t val_size;
uint8_t val[val_size];
}
A键:
00000000: 0f00 5345 5256 4552 5f50 524f ..SERVER_PRO
00000010: 544f 434f 4c TOCOL
数值:
00000010: 08 0048 5454 502f 312e 31 ..HTTP/1.1
A键:
00000010: 09 .
00000020: 0050 4154 485f 494e 464f .PATH_INFO
数值:
00000020: 0100 2f ../
依此类推,直到最终变量:
00000070: 0b00 5345 ..SE
00000080: 5256 4552 5f4e 414d 45 RVER_NAME
00000080: 0d 0065 7878 7861 ..exxxa
00000090: 6d70 6c65 2e63 6f6d mple.com
尾随的
0a
,我猜它是由socat
添加来分隔请求的。那么请求长度(0x98 字节)等于标头长度(4 字节)+ var 长度(0x94 字节)。
现在,Python 中的 TCP 套接字客户端[编写?] 如何与
uwsgi
对话?首先删除 0a
中尾随的 /tmp/request
,例如与 vim
+ xxd
。然后:
$ socat TCP4-LISTEN:1234,reuseaddr \
UNIX-CONNECT:/var/run/uwsgi-socket
$ cat /tmp/request | ncat example.com 1234 | less
(现在
socat
将 TCP 套接字 (*:1234
) 连接到位于 /var/run/uwsgi-socket
的 Unix 域套接字。ncat
让我们将由 uwsgi_curl
发送的请求发送到端口 1234
。)
另一方面,
uwsgi
也可以监听 TCP 套接字。所以另一个答案是,TCP 客户端无法直接连接到 Unix 域套接字服务器,只能通过诸如 socat
之类的代理连接。