原文地址:https://docs.python.org/3.6/howto/sockets.html
作者:Gordon McMillan
Sockets
本文着重讨论INET(IPv4) Sockets, 并限于STREAM(TCP) Sockets范畴。
历史
直到目前为止,在各类IPC(inter process communication)之中,socket仍然是最为流行的那个,尤其是对于跨平台通信来说,socket是无可替代的存在。
创建Socket
如果用简单粗暴的方式来表达,那么,在你打开本页面的链接之时,你的浏览器做的工作和下面的代码有点类似:
# create an INET, STREAMing socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# now connect to the web server on port 80 - the normal http port
s.connect(("www.python.org", 80))
当connect结束后,我们使用socket s 来发送一个request来获取页面的文本,此socket将会读取文本并被销毁。客户端的sockets通常只是一次性的。
而服务端的情况则会稍稍复杂一些。首先,web服务器创建了一个server socket:
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
这里有一些注意事项:我们使用了socket.gethostname(),所以此socket对于外界来说是可见的。而如果我们使用s.bind(('localhost', 80))或是s.bind(('127.0.0.0', 80))仍会得到服务端socket,不同的是只有本机才能看到这一socket。
使用s.bind(('', 80))则意味着本机拥有的任何地址均可获得该socket。
第二件比较重要的事情是:数字较小的端口通常已经为其他的通用程序保留了,所以如果你想做测试,挑一个较高的数字。
最后一句代码中,listen的参数告诉socket库我们最多保留5个连接请求,如果你其他的代码没问题,这个数量很充沛。
现在我们已经有了一个服务端socket,它监听着80端口,然后我们就可以创建web服务器的核心循环了。
while True:
# accept connections from outside
(clientsocket, address) = serversocket.accept()
# now do something with the clientsocket
# in this case, we'll pretend this is a threaded server
ct = client_thread(clientsocket)
ct.run()
通常来说,这一循环可以如下三种方式运作:调度一个线程去执行clientsocket,创建一个新进程来执行clientsocket,或是使用非阻塞sockets来重构项目,并用select来复合服务端socket与任何活跃的clientsocket,具体内容稍后详谈。
一定要认识到:以上就是一个服务端socket的全部工作,它不会发送或接收任何数据,它仅仅生产客户端socket。在一个客户端socket向绑定的主机和端口执行了connet()之后,clientsocket才会作为响应被创建。
一旦完成创建clientsocket的工作,我们就可以转而监听更多的连接,这两个“客户端”可以自由通信——它们使用的动态分配端口将会在通信结束后被回收。