zoukankan      html  css  js  c++  java
  • 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),此处不再赘述

  • 相关阅读:
    构建企业级数据湖?Azure Data Lake Storage Gen2实战体验(中)
    构建企业级数据湖?Azure Data Lake Storage Gen2实战体验(上)
    寻觅Azure上的Athena和BigQuery (二):神奇的PolyBase
    寻觅Azure上的Athena和BigQuery(一):落寞的ADLA
    Azure中国CDN全球覆盖功能初探
    第一次负责项目感悟
    C#读取静态类常量属性和值
    std::thread使用
    C#泛型编程
    C++模板类
  • 原文地址:https://www.cnblogs.com/cccc2019fzs/p/11966621.html
Copyright © 2011-2022 走看看