python中,想查看某个模块的源码位置:
import 模块名
help(模块名),在其中有个file项,就是源码或者dll的位置
或者:模块名.__file__
例如:
import socket
help(socket)或者socket.__file__
>>> import socket >>> socket.__file__ 'D:\\Python32\\lib\\socket.py'
可知,其源码在D:\Python32\lib中的socket.py文件中。
打开socket.py发现,其中并没有诸如socket(),accept(),listen(),connect()函数的直接实现,它们均是继承而来:
import _socket from _socket import * ...... ...... ...... class socket(_socket.socket): ...... ...... ......
接着,查看_socket模块来自哪里:
>>> import _socket >>> _socket.__file__ 'D:\\Python32\\DLLs\\_socket.pyd'
可以看见_socket模块来自D:\Python32\DLLs的_socket.pyd文件,_socket.pyd是python的一个动态模块,实际上dll文件,只是改了个后缀。这个文件是C编译而来。
此时,查看Python中的_socket模块:
查看socketmodule.c和socketmodule.h:
1.查看套接字对象的类型对象即sock_type(Modules/socketmodule.c):
声明:
/* A forward reference to the socket type object. The sock_type variable contains pointers to various functions, some of which call new_sockobject(), which uses sock_type, so there has to be a circular reference. */ static PyTypeObject sock_type;
定义:
/* Type object for socket objects. */ static PyTypeObject sock_type = { PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */ "_socket.socket", /* tp_name */ sizeof(PySocketSockObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)sock_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc)sock_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ sock_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ sock_methods, /* tp_methods */ sock_memberlist, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ sock_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ sock_new, /* tp_new */ PyObject_Del, /* tp_free */ };
2.套接字对象PySocketSockObject(Modules/socketmodule.h):
typedef struct { PyObject_HEAD SOCKET_T sock_fd; /* Socket file descriptor */ int sock_family; /* Address family, e.g., AF_INET */ int sock_type; /* Socket type, e.g., SOCK_STREAM */ int sock_proto; /* Protocol type, usually 0 */ PyObject *(*errorhandler)(void); /* Error handler; checks errno, returns NULL and sets a Python exception */ double sock_timeout; /* Operation timeout in seconds; 0.0 means non-blocking */ } PySocketSockObject;
3.函数sock_new(Modules/socketmodule.c):创建一个新的、未初始化的套接字对象
/* Create a new, uninitialized socket object. */ static PyObject * sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *new; new = type->tp_alloc(type, 0); if (new != NULL) { ((PySocketSockObject *)new)->sock_fd = -1; ((PySocketSockObject *)new)->sock_timeout = -1.0; ((PySocketSockObject *)new)->errorhandler = &set_error; } return new; }
4.函数sock_initobj(Modules/socketmodule.c):初始化新的套接字对象
/* Initialize a new socket object. */ /*ARGSUSED*/ static int sock_initobj(PyObject *self, PyObject *args, PyObject *kwds) { PySocketSockObject *s = (PySocketSockObject *)self; PyObject *fdobj = NULL; SOCKET_T fd = INVALID_SOCKET; int family = AF_INET, type = SOCK_STREAM, proto = 0; static char *keywords[] = {"family", "type", "proto", "fileno", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiO:socket", keywords, &family, &type, &proto, &fdobj)) return -1; if (fdobj != NULL && fdobj != Py_None) { #ifdef MS_WINDOWS /* recreate a socket that was duplicated */ if (PyBytes_Check(fdobj)) { WSAPROTOCOL_INFO info; if (PyBytes_GET_SIZE(fdobj) != sizeof(info)) { PyErr_Format(PyExc_ValueError, "socket descriptor string has wrong size, " "should be %zu bytes.", sizeof(info)); return -1; } memcpy(&info, PyBytes_AS_STRING(fdobj), sizeof(info)); Py_BEGIN_ALLOW_THREADS fd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, WSA_FLAG_OVERLAPPED); Py_END_ALLOW_THREADS if (fd == INVALID_SOCKET) { set_error(); return -1; } family = info.iAddressFamily; type = info.iSocketType; proto = info.iProtocol; } else #endif { fd = PyLong_AsSocket_t(fdobj); if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) return -1; if (fd == INVALID_SOCKET) { PyErr_SetString(PyExc_ValueError, "can't use invalid socket value"); return -1; } } } else { Py_BEGIN_ALLOW_THREADS fd = socket(family, type, proto); Py_END_ALLOW_THREADS if (fd == INVALID_SOCKET) { set_error(); return -1; } } init_sockobject(s, fd, family, type, proto); return 0; }
其中:
fd = socket(family, type, proto);为系统调用中的socket()函数。
函数原型为:
/* 以Linux为例 */ #include <sys/socket> int socket(int domain, int type, int protocol);
若函数调用成功,返回一个表示这个套接字的套接字文件描述符;否则返回-1。
init_sockobject(Modules/socketmodule.c)函数的定义:
/* Initialize a new socket object. */ static double defaulttimeout = -1.0; /* Default timeout for new sockets */ static void init_sockobject(PySocketSockObject *s, SOCKET_T fd, int family, int type, int proto) { s->sock_fd = fd; s->sock_family = family; s->sock_type = type; s->sock_proto = proto; s->errorhandler = &set_error; #ifdef SOCK_NONBLOCK if (type & SOCK_NONBLOCK) s->sock_timeout = 0.0; else #endif { s->sock_timeout = defaulttimeout; if (defaulttimeout >= 0.0) internal_setblocking(s, 0); } }
5.结构体数组sock_methods(Modules/socketmodule.c):列出套接字对象拥有的方法
sock_methods的结构体类型为PyMethodDef,其源码结构见:http://www.cnblogs.com/fortwo/archive/2013/04/25/3042502.html
/* List of methods for socket objects */ static PyMethodDef sock_methods[] = { {"_accept", (PyCFunction)sock_accept, METH_NOARGS, accept_doc}, {"bind", (PyCFunction)sock_bind, METH_O, bind_doc}, {"close", (PyCFunction)sock_close, METH_NOARGS, close_doc}, {"connect", (PyCFunction)sock_connect, METH_O, connect_doc}, {"connect_ex", (PyCFunction)sock_connect_ex, METH_O, connect_ex_doc}, {"detach", (PyCFunction)sock_detach, METH_NOARGS, detach_doc}, {"fileno", (PyCFunction)sock_fileno, METH_NOARGS, fileno_doc}, #ifdef HAVE_GETPEERNAME {"getpeername", (PyCFunction)sock_getpeername, METH_NOARGS, getpeername_doc}, #endif {"getsockname", (PyCFunction)sock_getsockname, METH_NOARGS, getsockname_doc}, {"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS, getsockopt_doc}, #if defined(MS_WINDOWS) && defined(SIO_RCVALL) {"ioctl", (PyCFunction)sock_ioctl, METH_VARARGS, sock_ioctl_doc}, #endif #if defined(MS_WINDOWS) {"share", (PyCFunction)sock_share, METH_VARARGS, sock_share_doc}, #endif {"listen", (PyCFunction)sock_listen, METH_O, listen_doc}, {"recv", (PyCFunction)sock_recv, METH_VARARGS, recv_doc}, {"recv_into", (PyCFunction)sock_recv_into, METH_VARARGS | METH_KEYWORDS, recv_into_doc}, {"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS, recvfrom_doc}, {"recvfrom_into", (PyCFunction)sock_recvfrom_into, METH_VARARGS | METH_KEYWORDS, recvfrom_into_doc}, {"send", (PyCFunction)sock_send, METH_VARARGS, send_doc}, {"sendall", (PyCFunction)sock_sendall, METH_VARARGS, sendall_doc}, {"sendto", (PyCFunction)sock_sendto, METH_VARARGS, sendto_doc}, {"setblocking", (PyCFunction)sock_setblocking, METH_O, setblocking_doc}, {"settimeout", (PyCFunction)sock_settimeout, METH_O, settimeout_doc}, {"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS, gettimeout_doc}, {"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS, setsockopt_doc}, {"shutdown", (PyCFunction)sock_shutdown, METH_O, shutdown_doc}, #ifdef CMSG_LEN {"recvmsg", (PyCFunction)sock_recvmsg, METH_VARARGS, recvmsg_doc}, {"recvmsg_into", (PyCFunction)sock_recvmsg_into, METH_VARARGS, recvmsg_into_doc,}, {"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS, sendmsg_doc}, #endif {NULL, NULL} /* sentinel */ };
例如其中的一个结构体如下:
{"_accept", (PyCFunction)sock_accept, METH_NOARGS,accept_doc}
说明套接字对象有一个名为_accept的方法,该方法对应的函数指针指向sock_accept函数,结合标志为METH_NOARGS(诸如此类标志在Include/methodobject.h定义),该方法的文档为accept_doc。
sock_accept函数的定义(Modules/socketmodule.c):
/* s._accept() -> (fd, address) */ static PyObject * sock_accept(PySocketSockObject *s) { sock_addr_t addrbuf;/* 用于accept函数,存储客户端地址信息 */ SOCKET_T newfd = INVALID_SOCKET; socklen_t addrlen; PyObject *sock = NULL; PyObject *addr = NULL; PyObject *res = NULL; int timeout; if (!getsockaddrlen(s, &addrlen)) return NULL; memset(&addrbuf, 0, addrlen); if (!IS_SELECTABLE(s)) return select_error(); BEGIN_SELECT_LOOP(s) Py_BEGIN_ALLOW_THREADS timeout = internal_select_ex(s, 0, interval); if (!timeout) { newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);/* accept调用成功返回newfd文件描述符,客户端的地址信息存储在addrbuf中 */ } Py_END_ALLOW_THREADS if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; } END_SELECT_LOOP(s) if (newfd == INVALID_SOCKET) return s->errorhandler(); sock = PyLong_FromSocket_t(newfd);/* 根据套接字文件描述符生成一个PyObject对象 */ if (sock == NULL) { SOCKETCLOSE(newfd); goto finally; } /* 获取socket地址,makesockaddr返回(host,port)二元组 */ addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, s->sock_proto); if (addr == NULL) goto finally; res = PyTuple_Pack(2, sock, addr);/* 将指向Pyobject对象的指针和地址组合成二元组 */ finally: Py_XDECREF(sock);/* 销毁引用 */ Py_XDECREF(addr); return res; } PyDoc_STRVAR(accept_doc, "_accept() -> (integer, address info)\n\ \n\ Wait for an incoming connection. Return a new socket file descriptor\n\ representing the connection, and the address of the client.\n\ For IP sockets, the address info is a pair (hostaddr, port)."); /* s.setblocking(flag) method. Argument: False -- non-blocking mode; same as settimeout(0) True -- blocking mode; same as settimeout(None) */
详细分析如下
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);是系统调用中的accpet函数。
函数原型为:
/* 以Linux为例 */ #include <sys/socket> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数成功调用后,返回一个新的套接字描述符表示客户端的连接,并且将客户端的IP地址、端口和协议族等信息存储在参数addr中。
服务器端接受请求后,与客户端进行通信的是accept()函数返回的新的套接字文件描述符,而不是通过在开始建立套接字时的文件描述符。
在python中的socket.accept()方法返回一个客户端套接字和地址的元组。现在分析下这个两部分的组合过程:
(1)newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);这里已经分析过了,主要是newfd和addrbuf。
(2)sock = PyLong_FromSocket_t(newfd);根据套接字文件描述符生成一个PyOject对象
socketmodule.h:
#define PyLong_FromSocket_t(fd) PyLong_FromLong((SOCKET_T)(fd))
longobject.c:
/* Create a new long int object from a C long int */ PyObject * PyLong_FromLong(long ival) { PyLongObject *v; unsigned long abs_ival; unsigned long t; /* unsigned so >> doesn't propagate sign bit */ int ndigits = 0; int sign = 1; CHECK_SMALL_INT(ival); if (ival < 0) { /* negate: can't write this as abs_ival = -ival since that invokes undefined behaviour when ival is LONG_MIN */ abs_ival = 0U-(unsigned long)ival; sign = -1; } else { abs_ival = (unsigned long)ival; } /* Fast path for single-digit ints */ if (!(abs_ival >> PyLong_SHIFT)) { v = _PyLong_New(1); if (v) { Py_SIZE(v) = sign; v->ob_digit[0] = Py_SAFE_DOWNCAST( abs_ival, unsigned long, digit); } return (PyObject*)v; } #if PyLong_SHIFT==15 /* 2 digits */ if (!(abs_ival >> 2*PyLong_SHIFT)) { v = _PyLong_New(2); if (v) { Py_SIZE(v) = 2*sign; v->ob_digit[0] = Py_SAFE_DOWNCAST( abs_ival & PyLong_MASK, unsigned long, digit); v->ob_digit[1] = Py_SAFE_DOWNCAST( abs_ival >> PyLong_SHIFT, unsigned long, digit); } return (PyObject*)v; } #endif /* Larger numbers: loop to determine number of digits */ t = abs_ival; while (t) { ++ndigits; t >>= PyLong_SHIFT; } v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->ob_digit; Py_SIZE(v) = ndigits*sign; t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( t & PyLong_MASK, unsigned long, digit); t >>= PyLong_SHIFT; } } return (PyObject *)v; }
(3)addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf),addrlen, s->sock_proto);根据addrbuf生成(host,port)元组。
查看makesockaddr函数(Modules/socketmodule.c)截取用到的部分:
/*ARGSUSED*/ static PyObject * makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) { if (addrlen == 0) { /* No address -- may be recvfrom() from known socket */ Py_INCREF(Py_None); return Py_None; } switch (addr->sa_family) { case AF_INET: { struct sockaddr_in *a; PyObject *addrobj = makeipaddr(addr, sizeof(*a));/* 获取addr中的host */ PyObject *ret = NULL; if (addrobj) { a = (struct sockaddr_in *)addr; ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));/* a->sin_port获得端口号,然后将网络字节序转换为主机字节序, host和port组成元组*/ Py_DECREF(addrobj);/* 销毁addrobj引用 */ } return ret; } ...... ...... ......
以上函数包含了makeipaddr函数。
查看makeipaddr函数(Modules/socketmodule.c):获取addr中的host部分信息
static PyObject * makeipaddr(struct sockaddr *addr, int addrlen) { char buf[NI_MAXHOST]; int error; error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); if (error) { set_gaierror(error); return NULL; } return PyUnicode_FromString(buf); }
系统调用getnameinfo函数原型:
/* 以Linux为例 */ #include <netdb.h> int getnameinfo(const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);
该函数以套接字地址为参数,返回其中的主机名(点分十进制字符串IP或域名)和服务名(端口号)。
说明这里的调用error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,NI_NUMERICHOST);中,buf中存储的是主机名。
6.结构体数组sock_memberlist(Modules/socketmodule.c):
sock_memberlist的结构体类型为PyMemberDef,其源码结构见:http://www.cnblogs.com/fortwo/archive/2013/04/25/3042502.html
/* SockObject members */ static PyMemberDef sock_memberlist[] = { {"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"}, {"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"}, {"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"}, {"timeout", T_DOUBLE, offsetof(PySocketSockObject, sock_timeout), READONLY, "the socket timeout"}, {0}, };
7.sock_doc(Modules/socketmodule.c):套接字对象的文档
/* Socket object documentation */ PyDoc_STRVAR(sock_doc, "socket([family[, type[, proto]]]) -> socket object\n\ \n\ Open a socket of the given type. The family argument specifies the\n\ address family; it defaults to AF_INET. The type argument specifies\n\ whether this is a stream (SOCK_STREAM, this is the default)\n\ or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\ specifying the default protocol. Keyword arguments are accepted.\n\ \n\ A socket object represents one endpoint of a network connection.\n\ \n\ Methods of socket objects (keyword arguments not allowed):\n\ \n\ _accept() -- accept connection, returning new socket fd and client address\n\ bind(addr) -- bind the socket to a local address\n\ close() -- close the socket\n\ connect(addr) -- connect the socket to a remote address\n\ connect_ex(addr) -- connect, return an error code instead of an exception\n\ _dup() -- return a new socket fd duplicated from fileno()\n\ fileno() -- return underlying file descriptor\n\ getpeername() -- return remote address [*]\n\ getsockname() -- return local address\n\ getsockopt(level, optname[, buflen]) -- get socket options\n\ gettimeout() -- return timeout or None\n\ listen(n) -- start listening for incoming connections\n\ recv(buflen[, flags]) -- receive data\n\ recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\ recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\ recvfrom_into(buffer[, nbytes, [, flags])\n\ -- receive data and sender\'s address (into a buffer)\n\ sendall(data[, flags]) -- send all data\n\ send(data[, flags]) -- send data, may not send all of it\n\ sendto(data[, flags], addr) -- send data to a given address\n\ setblocking(0 | 1) -- set or clear the blocking I/O flag\n\ setsockopt(level, optname, value) -- set socket options\n\ settimeout(None | float) -- set or clear the timeout\n\ shutdown(how) -- shut down traffic in one or both directions\n\ if_nameindex() -- return all network interface indices and names\n\ if_nametoindex(name) -- return the corresponding interface index\n\ if_indextoname(index) -- return the corresponding interface name\n\ \n\ [*] not available on all platforms!");
其中:
PyDoc_STRVAR的定义(Include/pymacro.h):
/* Define macros for inline documentation. */ #define PyDoc_VAR(name) static char name[] #define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) #ifdef WITH_DOC_STRINGS #define PyDoc_STR(str) str #else #define PyDoc_STR(str) "" #endif
补充:Linux网络编程中,通用的套接字地址结构和实际使用的套接字地址结构:
(1)通用套接字地址结构:
/* 以Linux为例 */ #incude <sys/socket.h> struct sockaddr{ sa_family_t sa_family; char sa_data[14]; };
(2)实际使用的套接字地址结构:
/* 以Linux为例 */ #incude <netinet/in.h> struct sockaddr_in{ sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; };
(3)IP地址结构:
/* 以Linux为例 */ #incude <netinet/in.h> typedef uint32_t in_addr_t; struct in_addr{ in_addr_t s_addr; };
由于结构体struct sockaddr和struct sockaddr_in的大小完全一致。通常使用struct sockaddr_in进行地址设置,之后将其强制转换struct sockaddr结构。