整个流程就是创建一个
socket
- socket.socket
- socket.bind
- socket.listen
- socket.accept
一些值得注意的地方:
- sock.setblocking
- set_close_exec(sock.fileno())
#!/usr/bin/env python
#-*-encoding:utf-8-*-
from tornado import httpserver
from tornado import ioloop
def handle_request(request):
message = "You requested %s\n" % request.uri
request.write("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s" % (
len(message), message))
request.finish()
http_server = httpserver.HTTPServer(handle_request)#在此打断点,来看下httpserver运行的过程。
http_server.listen(8888)
ioloop.IOLoop.instance().start()
http_server = httpserver.HTTPServer(handle_request)
程序会进入HTTPServer的__init__方法中
self.request_callback = handle_request
然后
1、http_server = httpserver.HTTPServer(handle_request)
TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
**kwargs)
跳转到TCPServer的__init__方法
self._sockets = {} # fd -> socket object此时fd还木有哦。
此处self._sockets声明为一个dict。
2、http_server.listen(8888)
此时调用TCPServer中的listen方法
def listen(self, port, address=""):
sockets = bind_sockets(port, address=address)
self.add_sockets(sockets)
整个socket的处理被封装在一个netutil.py文件中
def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags=None):
sockets = []
if address == "":
address = None
if not socket.has_ipv6 and family == socket.AF_UNSPEC:
family = socket.AF_INET
if flags is None:
flags = socket.AI_PASSIVE
for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM,
0, flags)):
af, socktype, proto, canonname, sockaddr = res
sock = socket.socket(af, socktype, proto)
set_close_exec(sock.fileno())
if os.name != 'nt':
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if af == socket.AF_INET6:
if hasattr(socket, "IPPROTO_IPV6"):
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
sock.setblocking(0)
sock.bind(sockaddr)
sock.listen(backlog)
sockets.append(sock)
return sockets
bind_sockets创建了一个socket
socket.socket(af, socktype, proto)
<socket object, fd=5, family=30, type=1, protocol=6>
等价于
socket.socket(socket.AF_INET,socket.SOCK_STREAM,IPPROTO_TCP)
fd即socketfd,由于UNIX套接字描述符也是文件描述符,所以统称fd.
接下来调用了
set_close_exec(sock.fileno())
这个方法定义在posix.py中
def set_close_exec(fd):
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
flags = fcntl.fcntl(fd, fcntl.F_GETFD)返回的flags为0;
fcntl.F_SETFD 对于fd设置文件描述符标志。此时FD_CLOEXEC = 1,即flags被置为1.
引用
F_GETFD 对应于fd的文件描述符标志作为函数值返回。当前只定义了一个文件描述符标志FD_CLOEXEC
FD_CLOEXEC用来设置文件的close-on-exec状态标准。在exec()调用后,close-on-exec标志为0的情况,此文件不被关闭。非零则在exec()后被关闭。默认close-on-exec状态为0,需要通过FD_CLOEXEC设置。
sock.setblocking(0)
引用
Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non-blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn’t find any data, or if a send() call can’t immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1) is equivalent to s.settimeout(None).
sock.bind(sockaddr)
sock.listen(backlog)
sockets.append(sock)
此时刚创建的socket加入到了sockets。
<socket object, fd=5, family=30, type=1, protocol=6>
<socket object, fd=6, family=2, type=1, protocol=6>
接着我们回到TCPServer中的
def listen(self, port, address=""):
sockets = bind_sockets(port, address=address)
self.add_sockets(sockets)
def add_sockets(self, sockets):
if self.io_loop is None:
self.io_loop = IOLoop.current()
for sock in sockets:
self._sockets[sock.fileno()] = sock#此处将sockets里面的socket转化为以sockfd为key socket为value 的字典。
add_accept_handler(sock, self._handle_connection,
io_loop=self.io_loop)
def add_accept_handler(sock, callback, io_loop=None):
if io_loop is None:
io_loop = IOLoop.current()
def accept_handler(fd, events):
while True:
try:
connection, address = sock.accept()#用于接收client的connect
except socket.error as e:
if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
return
raise
callback(connection, address)
io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ)
本文涉及ioloop以及iostream的地方都未介绍。
下文会继续debug ioloop以及iostream的整个流程。
参考资料:
http://www.kegel.com/c10k.html
http://kenby.iteye.com/blog/1159621
http://docs.python.org/2/library/fcntl.html
http://docs.python.org/2/library/socket.html