【发布时间】:2018-02-28 22:22:08
【问题描述】:
普通的python socket模块在创建socket时不支持AF_INET以外的协议:
来自 cpython socketmodule.c:
-
仅支持 AF_INET、AF_INET6 和 AF_UNIX 地址系列 可移植的方式,虽然支持 AF_PACKET、AF_NETLINK 和 AF_TIPC
在 Linux 下。
所以我已经着手使用 ctypes 直接从 libc 手动调用普通 BSD 套接字库的套接字、绑定、侦听和接受调用。 我可以创建套接字,将套接字绑定到一个地址,并将套接字置于侦听模式,这需要对我所做的继承 SockAddr_In 类的结构的引用进行转换:
CharArr14 = c_char * 14
In_Addr = c_uint32
CharArr8 = c_char * 8
class SockAddr(Structure):
_fields_ = [
('sa_len', c_uint8),
('sa_family', c_uint8),
('sa_data', CharArr14)
]
class SockAddr_In(Structure):
_fields_ = [
('sa_len', c_uint8),
('sa_family', c_uint8),
('sin_port', c_uint16),
('sin_addr', In_Addr),
('sin_zero', CharArr8)
]
但是当我尝试调用接受时,它传递了一个地址,内核将写入连接套接字的 SockAddr_In 结构信息,我收到与错误内存地址相对应的 EFAULT (errno 14)。
def accept_sdp_sock(self):
accept = libc.accept
logger.debug("Accepting socket on: {}".format(self.ip_addr))
# int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
# Why is this a bad address? Is it being deallocated?
# Maybe it isn't allocating until we fill it with data?
addr = SockAddr_In()
logger.debug("Memory address of addr struct: {}".format(addr))
afd = accept(self.fd,
cast(byref(addr), POINTER(SockAddr)),
sizeof(SockAddr_In))
# Check accept fd for errors
if afd == -1:
self.errno = get_errno()
logger.debug("Accept call failed: {} ".format(self.errno))
return afd
所以我们看到这个输出带有程序列出的内存地址
#truss -fead -s65535 -o truss_out python sdp_sock_cmd.py -l --address 192.168.66.140 --debug
2018-02-28 13:59:40,008 - DEBUG - This is a debug message
2018-02-28 13:59:40,009 - INFO - And an info
2018-02-28 13:59:40,009 - DEBUG - Creating SDP socket
2018-02-28 13:59:40,010 - DEBUG - Binding SDP socket to : 192.168.66.140
2018-02-28 13:59:40,011 - DEBUG - Memory address of addr struct: <ib_socks.SockAddr_In object at 0x80385d9e0>
2018-02-28 13:59:40,012 - DEBUG - Socket listening on: 192.168.66.140
2018-02-28 13:59:40,013 - DEBUG - Accepting socket on: 192.168.66.140
2018-02-28 13:59:40,014 - DEBUG - Memory address of addr struct: <ib_socks.SockAddr_In object at 0x80385d9e0>
2018-02-28 13:59:40,015 - DEBUG - Accept call failed: 14
在 truss 输出中我们看到:
18105: 0.288079361 accept(3,0x80385da30,0x10) ERR#14 'Bad address'
我尝试使用 libc 中的 malloc 进行分配,使用 ctypes 中的 create_string_buffer() 创建字符串缓冲区,但在这两种情况下我都看到了 EFAULT。为什么在这种情况下我会看到 EFAULT?如何使用 ctypes 使用 python 分配数据结构以允许内核将数据移动到用户空间?
【问题讨论】:
-
你应该定义
accept的argtypes和restype。
标签: python sockets ctypes cpython