Python 中的 socket 模块

本文参考PYTHON 网络编程 第一章

import socket
help(socket)

Functions:
    socket() -- create a new socket object
    socketpair() -- create a pair of new socket objects [*]
    fromfd() -- create a socket object from an open file descriptor [*]
    gethostname() -- return the current hostname
    gethostbyname() -- map a hostname to its IP number
    gethostbyaddr() -- map an IP number or hostname to DNS info
    getservbyname() -- map a service name and a protocol name to a port number
    getprotobyname() -- map a protocol name (e.g. ‘tcp‘) to a number
    ntohs(), ntohl() -- convert 16, 32 bit int from network to host byte order
    htons(), htonl() -- convert 16, 32 bit int from host to network byte order
    inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format
    inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)
    ssl() -- secure socket layer support (only available if configured)
    socket.getdefaulttimeout() -- get the default timeout value
    socket.setdefaulttimeout() -- set the default timeout value
    create_connection() -- connects to an address, with an optional timeout and optional source address.
   
简单的介绍一下这些函数的作用:

一、socket类方法(直接可以通过socket 类进行调用)

1、gethostbyname() -- map a hostname to its IP number

In [1]: import socket
In [2]: socket.gethostname()
Out[2]: ‘God‘

2、gethostbyname() -- map a hostname to its IP number

In [6]: import socket 
In [8]: hostname=socket.gethostname()
In [9]: print hostname
God
In [10]: socket.gethostbyname(hostname)
Out[10]: ‘127.0.1.1‘
In [11]: socket.gethostbyname(‘www.baidu.com‘)
Out[11]: ‘119.75.218.70‘

3、gethostbyaddr() -- map an IP number or hostname to DNS info

In [12]: import socket 
In [13]: socket.gethostbyaddr(‘God‘)
Out[13]: (‘God‘, [], [‘127.0.1.1‘])

In [14]: socket.gethostbyaddr(‘119.75.218.70‘)
---------------------------------------------------------------------------
herror                                    Traceback (most recent call last)
<ipython-input-14-612b876e1ed4> in <module>()
----> 1 socket.gethostbyaddr(‘119.75.218.70‘)

herror: [Errno 2] Host name lookup failure

gethostbyname 和 gethostbyaddr 两个函数时要依赖于DNS的(首先会从/etc/hosts获取结果,然后在到dns服务器中获取相应结果)。

4、协议名 、端口号相关
getservbyport() --  Return the service name from a port number and protocol name.
getservbyname() -- map a service name and a protocol name to a port number

In [1]: import socket
In [2]: socket.getservbyname(‘http‘)
Out[2]: 80
In [4]: socket.getservbyport(21)
Out[4]: ‘ftp‘

注释:getservbyport 和 getservbyname 两种方法获取的信息应该时从/etc/services 中获取

5、IPV4 地址转换
inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format
inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)

In [20]: add = ‘127.0.0.1‘
In [21]: packed_addr = socket.inet_aton(add)
In [23]: addr2 = socket.inet_ntoa(packed_addr)
In [24]: addr == addr2
Out[24]: True

inet_ntop(...)
        inet_ntop(af, packed_ip) -> string formatted IP address
        Convert a packed IP address of the given family to string format.
    
inet_pton(...)
        inet_pton(af, ip) -> packed IP address string
        Convert an IP address from string format to a packed string suitable for use with low-level network functions.

通常会使用 inet_pton 去判断一个地址的有效性。例如判断一个IPV6地址是否有效

def validip6addr(address):
    """
    Returns True if `address` is a valid IPv6 address.

        >>> validip6addr(‘::‘)
        True
        >>> validip6addr(‘aaaa:bbbb:cccc:dddd::1‘)
        True
        >>> validip6addr(‘1:2:3:4:5:6:7:8:9:10‘)
        False
        >>> validip6addr(‘12:10‘)
        False
    """
    try:
        socket.inet_pton(socket.AF_INET6, address)
    except (socket.error, AttributeError):
        return False

    return True

6、主机字节序和网络字节序之间相互转换(这种需要转换的数据仅仅限制于数字)
编写低层网络应用时,或许需要处理通过电缆在两台设备之间传送的低层数据。在这种操作中,需要把主机操作系统发出的数据转换成网络格式,或者做逆向转换,因为这两种数据的表示
方式不一样。(数据在电缆中的表示方式和在计算机中的表示方式是不一样的)

ntohs(), ntohl() -- convert 16, 32 bit int from network to host byte order
htons(), htonl() -- convert 16, 32 bit int from host to network byte order

注意:以上四个函数的参数全部都为数字,返回结构也全部都为数字

In [11]: data = 1234
In [19]: print ‘data:%s\nntohs:%s\nntohl:%s‘ %(data,socket.ntohs(data),socket.ntohl(data))
data:1234
ntohs:53764
ntohl:3523477504

In [20]: print ‘data:%s\nhtons:%s\nhtonl:%s‘ %(data,socket.htons(data),socket.htonl(data))
data:1234
htons:53764
htonl:3523477504

以上所有的函数都属于socket 类方法,直接通过socket 类即可调用

二、socket 实例调用
1、创建一个socket 实例
socket([family[, type[, proto]]]) -> socket object
Open a socket of the given type.  The family argument specifies the address family; it defaults to AF_INET.  The type argument specifies
whether this is a stream (SOCK_STREAM, this is the default) or datagram (SOCK_DGRAM) socket.  The protocol argument defaults to 0,
specifying the default protocol.  Keyword arguments are accepted.

根据上面的英文解释:
family 默认值为 AF_INET 通常为默认即可
type   选择SOCK_STREAM(TCP) 和 SOCK_DGRAM(UDP) ,默认值为SOCK_STREAM
proto 默认为0 ,通常我们不用关系

建立一个tcp 的 socket 实例

In [6]: import socket
In [7]: s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

OK,有了socket 实例,就可以使用很多socket 实例的方法了。这些方法有那些呢?

|  Methods of socket objects (keyword arguments not allowed):
 |  
 |  accept() -- accept a connection, returning new socket and client address
 |  bind(addr) -- bind the socket to a local address
 |  close() -- close the socket
 |  connect(addr) -- connect the socket to a remote address
 |  connect_ex(addr) -- connect, return an error code instead of an exception
 |  dup() -- return a new socket object identical to the current one [*]
 |  fileno() -- return underlying file descriptor
 |  getpeername() -- return remote address [*]
 |  getsockname() -- return local address
 |  getsockopt(level, optname[, buflen]) -- get socket options
 |  gettimeout() -- return timeout or None
 |  listen(n) -- start listening for incoming connections
 |  makefile([mode, [bufsize]]) -- return a file object for the socket [*]
 |  recv(buflen[, flags]) -- receive data
 |  recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)
 |  recvfrom(buflen[, flags]) -- receive data and sender‘s address
 |  recvfrom_into(buffer[, nbytes, [, flags])
 |    -- receive data and sender‘s address (into a buffer)
 |  sendall(data[, flags]) -- send all data
 |  send(data[, flags]) -- send data, may not send all of it
 |  sendto(data[, flags], addr) -- send data to a given address
 |  setblocking(0 | 1) -- set or clear the blocking I/O flag
 |  setsockopt(level, optname, value) -- set socket options
 |  settimeout(None | float) -- set or clear the timeout
 |  shutdown(how) -- shut down traffic in one or both directions

2、设定并获取默认的套接字超时时间

In [6]: import socket
In [7]: s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
In [9]: s.gettimeout()  # 此时gettimeout 返回None,说明这个socket 没有设置超时处理

In [10]: s.settimeout(60)
In [11]: s.gettimeout()
Out[11]: 60.0

3、修改、查看套接字属性 setsockopt 和 getsockopt

通过socket 实例 s  获取 的帮助如下:

help(s.setsockopt)

setsockopt(...) method of socket._socketobject instance
    setsockopt(level, option, value)
    Set a socket option.  See the Unix manual for level and option.The value argument can either be an integer or a string.

help(s.getsockopt)

getsockopt(...) method of socket._socketobject instance
    getsockopt(level, option[, buffersize]) -> value
    Get a socket option.  See the Unix manual for level and option. If a nonzero buffersize argument is given, the return value is a string of that length; otherwise it is an integer.

其中 setsockopt 和  getsockopt 中的 level、option 参数需要查看uninx 帮助手册去和获得相关信息

man 7 socket 可以看到相应的相关信息,其中有一段如下信息:

Socket options
       The socket options listed below can be set by using setsockopt(2) and read with getsockopt(2) with the socket level set to SOL_SOCKET for all sock‐ets.  Unless otherwise noted, optval is a pointer to an int.

介绍了 level 为 SOL_SOCKET 以及响应的option 字段信息

Example: 设置socket 发送和接收的缓冲区大小

In [1]: import socket
In [3]: s = socket.socket(socket.AF_INET,socket.SOL_SOCKET)
In [4]: s.getsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF)
Out[4]: 87380
In [5]: s.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF)
Out[5]: 16384
In [6]: s.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,4096)
In [7]: s.getsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF)
Out[7]: 8192
In [8]: s.setsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF,4096)
In [9]: s.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF)
Out[9]: 8192

4、把套接字改成阻塞或非阻塞模式

默认情况下,TCP套接字处于阻塞模式中。也就是说,除非完成了某项操作,否则不会把控制权交还给程序

通过socket 实例 s  获取 的帮助如下:

setblocking(...) method of socket._socketobject instance
    setblocking(flag)
    Set the socket to blocking (flag is true) or non-blocking (false).
    setblocking(True) is equivalent to settimeout(None);
    setblocking(False) is equivalent to settimeout(0.0)

In [2]: s = socket.socket(socket.AF_INET,socket.SOL_SOCKET)
In [3]: s.setblocking(True)

5、重用套接字地址

不管连接是被有意还是无意关闭,有时你想始终在同一个端口上运行套接字服务器。某些情
况下,如果客户端程序需要一直连接指定的服务器端口,这么做就很有用,因为无需改变服务器
端口

Example:

#! /usr/bin/env python
# _*_ coding: utf-8 _*_

import socket
import sys

def reuse_socket_addr():
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    old_state = sock.getsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR)
    print "Old sock state: %s" %old_state

    sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    new_state =  sock.getsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR)
    print "New sock state: %s" %new_state

    local_port = 8282
    srv = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 此时 socket 没有开启从用
    srv.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,0) 
    srv.bind((‘‘,local_port))
    srv.listen(1)
    print "Listening on port: %s " %local_port

    while True:
        try:
            conn, addr = srv.accept()
            print "Connected by %s:%s" %(addr[0],addr[1])
        except KeyboardInterrupt:
            break
        except socket.error,msg:
            print ‘%s‘ %msg

if __name__ == "__main__":
    reuse_socket_addr()

运行后在另一个终端对8282 端口进行重复的 telnet 操作,看看会出现什么效果

$ python testsocketreuse.py 
Old sock state: 0
New sock state: 1
Listening on port: 8282 
Connected by 127.0.0.1:52733

退出后再次执行测试的 testsocketreuse.py 脚本

Old sock state: 0
New sock state: 1
Traceback (most recent call last):
  File "testsocketreuse.py", line 33, in <module>
    reuse_socket_addr()
  File "testsocketreuse.py", line 19, in reuse_socket_addr
    srv.bind((‘‘,local_port))
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use

此时发现端口已经被重用,无法再次执行,需要等待重用的端口资源释放后此可以执行成功。

启用端口重用:

    # 此时 socket 没有开启从用
    srv.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

此时,再反复的执行此脚本,则没有发生端口重用的现象。

时间: 2024-10-19 17:28:02

Python 中的 socket 模块的相关文章

Python中的socket 模块

Python 提供了两个基本的 socket 模块.第一个是 Socket,它提供了标准的 BSD Sockets API.第二个是 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发. 下面先讲的是Socket模块功能 1.Socket 类型 套接字格式: socket(family,type[,protocal]) 使用给定的地址族.套接字类型.协议编号(默认为0)来创建套接字.socket类型描述socket.AF_UNIX只能够用于单一的Unix系统进程间通信so

Python中的socket模块

Python网络编程离不开socket模块 1. socket模块的简单使用,以开发一个简单的命令行工具为例,如下 1.1 socket client 端代码 1 # -*- coding:utf-8 -*- 2 # Author:Wong Du 3 4 import socket 5 6 # 创建一个socket对象 7 client = socket.socket() 8 # 与服务器端建立连接 9 client.connect( ('localhost', 9494) ) 10 11 12

python 中的socket

python中利用socket模块来实现对各种底层通讯的封装,支持tcp/udp协议,为编制c/s类的程序提供了便利. 最常见的用法: 如ftp_server: 1 import socketserver 2 class Mysocketserver(socketserver.BaseRequestHandler): 3 def handle(self): 4 while True: 5 try: 6 self.data=self.request.recv(1024).strip() 7 pri

浅析Python中的struct模块

最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的总结. 了解c语言的人,一定会知道struct结构体在c语言中的作用,它定义了一种结构,里面包含不同类型的数据(int,char,bool等等),方便对某一结构对象进行处理.而在网络通信当中,大多传递的数据是以二进制流(binary data)存在的.当传递字符串时,不必担心太多的问题,而当传递诸如int.char之

python中的select模块

介绍: Python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统) select方法: 进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生时,进程被阻塞:当一个或者多个文件描述符事件发生时,进程被唤醒. 当我们调用select()时: 1 上下文切换转换为内核态 2 将fd从用户空间复制到内

Python中的random模块,来自于Capricorn的实验室

Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 <= n < 1.0 random.uniform random.uniform的函数原型为:random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限.如果a > b,则生成的随机数n: a <= n <= b.如果 a <

python中查看可用模块

1.这种方式的问题是,只列出当前import进上下文的模块. 进入python命令行.输入以下代码: >>>import sys >>>sys.modules 2.在python命令行下输入: >>>help() help>modulespython中查看可用模块,布布扣,bubuko.com

python中动态导入模块

如果导入的模块不存在,Python解释器会报 ImportError 错误: >>> import something Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named something 有的时候,两个不同的模块提供了相同的功能,比如 StringIO 和 cStringIO 都提供了Strin

Python中的random模块

Python中的random模块 (转载自http://www.cnblogs.com/yd1227/archive/2011/03/18/1988015.html) Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 <= n < 1.0 random.uniform random.uniform的函数原型为:random.uniform(a, b),