python提供的网络接口API和Linux Socket API间的关系探究 liushu

首先以一个简单的hello/hi网络聊天程序作为示例,它使用了python提供的Socket API接口,程序的功能就是:客户端向服务器发送一条消息,服务器端返回一条消息给客户端

server.py

import socket

host='127.0.0.1'
port=1234
serv_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serv_sock.bind((host,port))
serv_sock.listen(10)
#接收客户端套接字
clnt_sock,addr=serv_sock.accept()
msg=clnt_sock.recv(1024)
str_msg=msg.decode("utf-8")
#返回给客户端消息
r_msg="Hi,"+str_msg[10:]
clnt_sock.send(r_msg.encode("utf-8"))
#关闭连接
serv_sock.close()
clnt_sock.close()

client.py

import socket

host='127.0.0.1'
port=1234
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host,port))
#向服务器发送数据
msg=input("input:")
sock.send(msg.encode("utf-8"))
#接收服务器返回的消息
recive=sock.recv(1024)
print(recive)
sock.close()

在上述这个简单的聊天程序中,调用了python提供的下列网络函数

  • socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • socket.connect(address),其中address是一个元组(host,port)
  • socket.bind(address)
  • socket.listen([backlog])
  • socket.accept(),返回一个元组 (conn,address)
  • socket.send(bytes[, flags])
  • socket.recv(bufsize[, flags])

python的官方文档上提到,socket模块提供了访问BSD Socket的接口,上述的网络函数应该和系统提供的Socket API对应。使用strace这个工具,可以查看一个应用程序使用的的系统调用,接下来我会使用strace检查客户端用到的Linux Socket API。

只需要启动服务端,然后输入

strace python ./client.py

即可查看系统调用,其中和网络有关的系统调用信息如下

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 
connect(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
sendto(3, "Hello,I'm liu", 13, 0, NULL, 0) = 13
recvfrom(3, "Hi,liu", 1024, 0, NULL, NULL) = 6
write(1, "Hi,liu\n", 7Hi,liu) = 7
close(3) = 0

可以从这些信息中看的python提供的网络接口API和Linux Socket API间一一对应的关系:

  • 在通过socket.socket()创建套接字时,底层调用的是socket()这个API,创建的套接字文件描述符是3(Shell启动的进程会打开三个与标准输入输出相关的文件,描述符为0,1,2)
  • socket.connect()对应的是connect() API,第一个参数指明文件描述符3,即在前面创建的套接字上建立连接,然后python帮我们自动填充了sockaddr类型的结构体
  • 可以看到,尽管创建的是流式套接字,但底层发送、接收数据还是使用的sendto和recvfrom,不过后两个参数(目的/源地址及其长度)被设为了NULL,《Unix网络编程》中说,在TCP中,connect函数调用后可以使用sendto及recvfrom,但还是不清楚python为什么这样实现socket.send()和socket.recv()

服务器端的系统调用类似,其中socket.accept()函数调用了accpet来实现,并创建了新套接字(描述符为4),此处不再赘述

原文地址:https://www.cnblogs.com/cccc2019fzs/p/11966621.html