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结构。

 

 

 

posted on 2013-04-25 15:41  101010  阅读(2027)  评论(0编辑  收藏  举报