Python socket基础函数

24 篇文章 0 订阅

python模块介绍- socket(1)



socket模块展示了使用BSD socketAPI在网络上进行通信的低级的C API。它包括用于处理实际数据信道socket类,还包括用于与网络相关的任务的功能,比如转换一个服务器的名字为地址和格式化要发送的数据
 
1 socket– 网络通信

套接字是程序使用通信信道用来本地或网络上来回传送数据的一个端点。套接字有两个基本属性用来控制发送数据:地址族控制的OSI网络层使用的协议,套接字类型控制输送层协议。

Python支持的3种地址族
最常见的AF_INET,用于IPv4的互联网寻址。几乎目前所有互联网联网使用IP版本4。
AF_INET6用于IPv6互联网寻址。IPv6是“下一代”版本的互联网协议。它支持128位的地址,流量控制和IPv4不支持的路由功能。IPv6有限使用,但持续增长。
AF_UNIX是UNIX域套接字(UDS),是POSIX兼容的系统上进程间的通信协议。UDS的实现通常允许操作系统不用通过网络堆栈在进程间直接通信。这比使用AF_INET更高效,但使用文件系统被作为命名空间进行寻址,UDS限制在同一系统。吸引力在于在IPC使用UDS,比如命名管道或共享内存的编程接口和IP网络一致。这应用程序可以使用网络通信同样的代码在单机上实现有效的通信机制。
 
套接字类型通常是为SOCK_DGRAM用户数据报协议(UDP)SOCK_STREAM传输控制协议(TCP)。 tcp一般用户传送大量数据,udp一般用于传送少量数据或者多播。

Socket展示了使用BSDsocket接口进行网络通信的低层CAPI。它包括socket类,用于处理实际数据通道,还包含网络相关的功能,比如转换服务器名为地址,格式化要发送的数据。

1.1 寻址、协议家族和socket类型
 
1.1.1 查找主机:

要查找当前主机的名字,可以使用gethostname()

import socket
#获取主机名
print socket.gethostname()



socket.gethostbyname(hostname)

翻译的主机名IPv4地址格式。以字符串形式返回的IPv4地址,如'100.50.200.5“。如果是一个IPv4地址的主机名,它原封不动地返回。更完整的接口参见gethostbyname_ex()。gethostbyname()的不支持IPv6名称解析,可以使用getaddrinfo()获取IPv4/v6双协议栈支持。
 
   import socket
   for host in [ ’homer’, ’www’, ’www.python.org’, ’nosuchname’ ]:
   try:
       print ’%s : %s’ % (host, socket.gethostbyname(host))
   except socket.error, msg:
       print ’%s : %s’ % (host, msg)

   
   执行结果:
   # python socket_gethostbyname.py
   homer : [Errno -2] Name or service not known
   www : [Errno -2] Name or service not known
   www.python.org : 82.94.164.162
   nosuchname : [Errno -2] Name or service not known  

 
 
socket.gethostbyname_ex(hostname)

翻译的主机名IPv4地址格式的扩展接口。返回一个三元组(hostname,aliaslist,ipaddrlist),gethostbyname_ex()不支持IPv6名称解析,可以使用getaddrinfo()获取IPv4/v6双协议栈支持。

   import socket
 
   for host in [ 'homer', 'www', 'www.python.org', 'nosuchname' ]:
       print host
       try:
            hostname, aliases, addresses =socket.gethostbyname_ex(host)
            print '  Hostname:', hostname
            print '  Aliases :', aliases
            print ' Addresses:', addresses
       except socket.error as msg:
            print 'ERROR:', msg
       print


       
   执行结果:
  
 # python socket_gethostbyname_ex.py
   homer
   ERROR: [Errno -2] Name or service not known
 
   www
   ERROR: [Errno -2] Name or service not known
 
   www.python.org
     Hostname: www.python.org
     Aliases : []
    Addresses: ['82.94.164.162']
 
   nosuchname
   ERROR: [Errno -2] Name or service not known

   
socket.getfqdn([name])

   返回一个完全的域名。如果名字被省略或为空,默认为本地主机。首先使用gethostbyaddr()返回的主机名来查找名称,然后是主机的别名。被选中的第一名称,其中包括一个时期。如果没有完全合格的域名,返回的gethostname()返回的主机名。   
 
   import socket
 
   for host in [ 'homer', 'www' ]:
       print '%6s : %s' % (host, socket.getfqdn(host)) 


 
   执行结果:
   $ python socket_getfqdn.py
   homer : homer.hellfly.net
   www : homer.hellfly.net 


 
socket.gethostbyaddr(ip_address)

返回一个三元组(hostname,aliaslist,ipaddrlist),支持IPv4和IPv6。   
   import socket
 
   hostname, aliases, addresses = socket.gethostbyaddr('172.23.191.53')
 
   print 'Hostname :', hostname
   print 'Aliases  :', aliases
   print 'Addresses:', addresses

   
   执行结果:
 
  $ python socket_gethostbyaddr.py
   Hostname : homer.hellfly.net
   Aliases : [‘8.1.168.192.in-addr.arpa’]
   Addresses: [‘192.168.1.8’]

1.1.2 查找服务信息:

      socket.getservbyname(servicename[,protocolname])
翻译的互联网服务名称和协议的名称为端口号。协议名称,如果有,应该是“TCP”或“UDP”,否则,任何协议都将匹配。
 
  
  import socket
    from urlparse import urlparse
 
    for url in [ 'http://www.python.org',
                 'https://www.mybank.com',
                 'ftp://prep.ai.mit.edu',
                'gopher://gopher.micro.umn.edu',
                 'smtp://mail.example.com',
                 'imap://mail.example.com',
                 'imaps://mail.example.com',
                 'pop3://pop.example.com',
                 'pop3s://pop.example.com',
                 ]:
        parsed_url = urlparse(url)
        port = socket.getservbyname(parsed_url.scheme)
        print '%6s : %s' % (parsed_url.scheme,port)

       
    执行结果:
    # python socket_getservbyname.py
      http : 80
     https : 443
       ftp : 21
    gopher : 70
      smtp : 25
      imap : 143
     imaps : 993
      pop3 : 110
     pop3s : 995


 
socket.getservbyport(port[,protocolname])

翻译的Internet端口号和协议名称为服务名,服务。协议名称,如果有,应该是“TCP”或“UDP”,否则,任何协议都将匹配。
 
    import socket
    import urlparse
 
    for port in [ 80, 443, 21, 70, 25, 143,993, 110, 995 ]:
        print urlparse.urlunparse(
            (socket.getservbyport(port),'example.com', '/', '', '', '')
            )


    执行结果:
    # python socket_getservbyport.py
    http://example.com/
    https://example.com/
    ftp://example.com/
    gopher://example.com/
    smtp://example.com/
    imap://example.com/
    imaps://example.com/
    pop3://example.com/
    pop3s://example.com/


 
socket.getprotobyname(protocolname)


翻译的互联网协议名(例如,“ICMP”),为适合的socket()函数的第三个参数(可选)的常量。这通常只是“原始”模式(SOCK_RAW)需要,普通socket模式会自动选择正确的协议,设置为0或者或略就可。 

   
 import socket
 
    def get_constants(prefix):
        """Create a dictionarymapping socket module
        constants to their names.
        """
        return dict( (getattr(socket, n), n)
                     for n in dir(socket)
                     if n.startswith(prefix)
                     )
 
    protocols = get_constants('IPPROTO_')
    print protocols
 
    for name in [ 'icmp', 'udp', 'tcp' ]:
        proto_num = socket.getprotobyname(name)
        print proto_num
        const_name = protocols[proto_num]
        print '%4s -> %2d (socket.%-12s =%2d)' % \
            (name, proto_num, const_name,getattr(socket, const_name))

    执行结果:
    # python socket_getprotobyname.py
    
{0: 'IPPROTO_IP', 1: 'IPPROTO_ICMP', 2:'IPPROTO_IGMP', 4: 'IPPROTO_IPIP', 6: 'IPPROTO_TCP', 8: 'IPPROTO_EGP', 12:'IPPROTO_PUP', 17: 'IPPROTO_UDP', 22: 'IPPROTO_IDP', 29: 'IPPROTO_TP', 41:'IPPROTO_IPV6', 43: 'IPPROTO_ROUTING', 44: 'IPPROTO_FRAGMENT', 46:'IPPROTO_RSVP', 47: 'IPPROTO_GRE', 50: 'IPPROTO_ESP', 51: 'IPPROTO_AH', 58:'IPPROTO_ICMPV6', 59: 'IPPROTO_NONE', 60: 'IPPROTO_DSTOPTS', 103:'IPPROTO_PIM', 255: 'IPPROTO_RAW'}
    1
    icmp -> 1 (socket.IPPROTO_ICMP =  1)
    17
     udp -> 17 (socket.IPPROTO_UDP  = 17)
    6
     tcp -> 6 (socket.IPPROTO_TCP  =  6)

  协议的数值是标准化的,在socket中以前缀IPPROTO_开头的常量存在。


1.1.3 查找服务器地址:

socket.getaddrinfo(host, port, family=0,socktype=0, proto=0, flags=0)

翻译host/port参数为成一个5元组(包含创建连接至该服务的socket的必需参数)构成的序列。主机是一个域名,IPv4/v6的地址“或None。端口是一个字符串:服务的名称,如'http',数字端口号或None。host和port都为None,传递的就是底层cAPI的NULL。
family可以填写socktype和proto参数以缩写返回地址的列表。0为最大范围。可以有1或者多个AI_*常量构成。比如AI_NUMERICHOST将禁止域名解析。如果主机是一个域名将引发一个错误。
该函数返回一个具有以下结构的5- 元组列表:

(family, socktype, proto, canonname,sockaddr)
family,socktype,proto都是传递给的整数。如果flags包含AI_CANONNAME,canonname表示canonical名,否则就为空。sockaddr是描述套接字地址的元组:AF_INET返回为(address,port),AF_INET6返回为AF_INET6。其格式依赖于返回的家庭((地址,port)2AF_INET,元组(地址,端口流量信息,范围ID)四元AF_INET6),并会传递给Socket.connect()的方法。
下例为www.python.org的地址信息。
>>> import socket
>>>socket.getaddrinfo("www.python.org", 80, 0, 0, socket.SOL_TCP)
[(10, 1, 6, '', ('2001:888:2000:d::a2',80, 0, 0)), (2, 1, 6, '', ('82.94.164.162', 80))]
 
   import socket
 
   def get_constants(prefix):
       """Create a dictionary mapping socket module
       constants to their names.
       """
       return dict( (getattr(socket, n), n)
                    for n in dir(socket)
                     if n.startswith(prefix)
                     )
 
   families = get_constants('AF_')
   types = get_constants('SOCK_')
   protocols = get_constants('IPPROTO_')
 
   for response in socket.getaddrinfo('www.python.org', 'http'):
 
       # Unpack the response tuple
       family, socktype, proto, canonname, sockaddr = response
 
       print 'Family        :',families[family]
       print 'Type          :',types[socktype]
       print 'Protocol      :',protocols[proto]
       print 'Canonical name:', canonname
       print 'Socket address:', sockaddr
       print
       


   执行结果:
   
# python socket_getaddrinfo.py
   Family        : AF_INET6
   Type          : SOCK_STREAM
   Protocol      : IPPROTO_TCP
   Canonical name:
   Socket address: ('2001:888:2000:d::a2', 80, 0, 0)
 
   Family        : AF_INET6
   Type          : SOCK_DGRAM
   Protocol      : IPPROTO_UDP
   Canonical name:
   Socket address: ('2001:888:2000:d::a2', 80, 0, 0)
 
   Family        : AF_INET6
   Type          : SOCK_STREAM
   Protocol      :
   Traceback (most recent call last):
     File "socket_getaddrinfo.py", line 32, in <module>
       print 'Protocol      :',protocols[proto]
   KeyError: 132

   
   设置了AI_CANONNAME的实例:
  
 import socket
 
   def get_constants(prefix):
       """Create a dictionary mapping socket module
       constants to their names.
       """
       return dict( (getattr(socket, n), n)
                     for n in dir(socket)
                     if n.startswith(prefix)
                     )
 
   families = get_constants('AF_')
   types = get_constants('SOCK_')
   protocols = get_constants('IPPROTO_')
 
   for response in socket.getaddrinfo('www.doughellmann.com', 'http',
                                      socket.AF_INET,      # family
                                      socket.SOCK_STREAM,  # socktype
                                      socket.IPPROTO_TCP,  # protocol
                                       socket.AI_CANONNAME, # flags
                                       ):
       
       # Unpack the response tuple
       family, socktype, proto, canonname, sockaddr = response
 
       print 'Family        :',families[family]
       print 'Type          :',types[socktype]
       print 'Protocol      :',protocols[proto]
       print 'Canonical name:', canonname
       print 'Socket address:', sockaddr
       print

       
   执行结果:
  
 # python socket_getaddrinfo_extra_args.py
   Family        : AF_INET
   Type          : SOCK_STREAM
   Protocol      : IPPROTO_TCP
   Canonical name: www.doughellmann.com
   Socket address: ('208.97.185.20', 80)

1.1.4 IP地址表示:

C网络程序使用structsockaddr来表示IP地址,是二进制,而不是python中常见的二进制。IPv4在python和c之间的切换使用inet_aton()和inet_ntoa()。
 
socket.inet_aton(ip_string)

把字符串格式的ip地址转换为 c语言格式,比如‘192.168.1.1’->c0a80101。支持IPV6需要使用inet_pton。
socket.inet_ntoa(packed_ip)和上面的刚好相反:
 
    import binascii
    import socket
    import struct
    import sys
 
    for string_address in [ '192.168.1.1','127.0.0.1' ]:
        packed =socket.inet_aton(string_address)
        print 'Original:', string_address
        print 'Packed  :', binascii.hexlify(packed)
        print 'Unpacked:',socket.inet_ntoa(packed)
        print


   
    注意hexlify是返回2进制数据的16进制表示。
    执行结果:
   
   
    适用于ipv6的例子:
    import binascii
    import socket
    import struct
 # python socket_address_packing.py
    Original: 192.168.1.1
    Unpacked: 192.168.1.1
 
    Original: 127.0.0.1
    Unpacked: 127.0.0.1 

 
   import sys
 
    string_address ='2002:ac10:10a:1234:21e:52ff:fe74:40e'
    packed = socket.inet_pton(socket.AF_INET6,string_address)
 
    print 'Original:', string_address
    print 'Packed  :', binascii.hexlify(packed)
    print 'Unpacked:',socket.inet_ntop(socket.AF_INET6, packed)   

   
    执行结果:
   
 # python socket_ipv6_address_packing.py
    Original:2002:ac10:10a:1234:21e:52ff:fe74:40e
    Packed : 2002ac10010a1234021e52fffe74040e
    Unpacked:2002:ac10:10a:1234:21e:52ff:fe74:40e  

 
注意IPV6本身就是二进制表示的,且inet_pton()and inet_ntop()只适用于linux平台。
参考资料:IPv6(http://en.wikipedia.org/wiki/IPv6)
OSI NetworkingModel (http://en.wikipedia.org/wiki/OSI_model)
AssignedInternet Protocol Numbers

转自:http://www.2cto.com/kf/201303/194689.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值