socket- 低层级网络接口

这个模块提供访问BSD socket接口, 它是可以使用的在所有的unix 系统,windows ,mac os x等平台


注意 一些行为可能是依赖于平台,因为是对操作系统放入socket api进行调用

有关socket编程的介绍,请参阅以下章节:

介绍 4.3 BSD 进程间通讯 


Python 接口是Unix 系统调用的直接翻译,

socket() 函数返回一个接口对象,实现了各种socket系统调用。

参数类型是相比C接口是级别稍高的 

socket addresses 是表示如下:

一个简单的字符串是用于AF_UNIX address family
结构

A pair (host, port) 是用于 AF_INET address family

hots是一个字符代表 是一个主机名在,端口是一个整数


对于AF_INET6  address family, 使用4个元素的元组(host, port, flowinfo, scopeid)

 flowinfo and scopeid代表 sin6_flowinfo and sin6_scope_id 成员在结构sockaddr_in6
 
 
 对于IPV4地址, 2个特定的类型是接收来代替一个主机地址 
 
 版本2.6中的新功能:

addr_type 是 TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, or TIPC_ADDR_ID 之一

scope 是TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and TIPC_NODE_SCOPE. 之一

所有错误都会引发异常.通常的异常时错误的参数类型和 内部不足类型

通过 setblocking()支持非堵塞模式 ,是基于timeouts 通过settimeout().

这个模块socket 导出下面的常量和函数

异常socket错误:

这个异常时抛出socket相关的错误。

exception socket.herror

这个错误是抛出用于地址相关的错误, 即对于函数使用h_errno 在C API,

包含 gethostbyname_ex() and gethostbyaddr().


socket.AF_UNIX
socket.AF_INET
socket.AF_INET6

这些常量表示地址(和协议)系列,用于socket的第一个参数

如果AF_UNIX 是没有定义 那么这个协议不支持

socket.SOCK_STREAM
socket.SOCK_DGRAM
socket.SOCK_RAW
socket.SOCK_RDM
socket.SOCK_SEQPACKET

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建套接字

那些常量表示socket类型,用于socket的第2个参数

. (Only SOCK_STREAM and SOCK_DGRAM appear to be generally useful.)

SO_*
socket.SOMAXCONN
MSG_*
SOL_*
IPPROTO_*
IPPORT_*
INADDR_*
IP_*
IPV6_*
EAI_*
AI_*
NI_*
TCP_*

这些表单的常量  

socket.create_connection(address[, timeout[, source_address]])


连接到一个TCP 服务侦听地址(一个2元素元组(host,port)

返回一个socket对象

import socket
import time
s=socket.create_connection(("192.168.137.2",8080))

这是一个更高级的函数相比socket.connect()

如果host 不是一个非数字的主机名,它将尝试接续它用于AF_INET and AF_INET6, 

传递可选的timeout参数会设置超时时间 在尝试连接前

设置超时时间:
import socket
import time
import datetime
print  datetime.datetime.now()
try:
 s=socket.create_connection(("1.1.1.2",8080),timeout=30)
except:
 print  datetime.datetime.now()

C:\Python27\python.exe C:/Users/TLCB/PycharmProjects/untitled2/http/t3.py
2020-02-20 11:10:47.477000
None
2020-02-20 11:11:08.482000

这么设置是无效的

正确做法:

import socket
import time
import datetime
socket.setdefaulttimeout(34)

print  datetime.datetime.now()
print socket.getdefaulttimeout()
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(40)
    s.connect(('1.1.1.1',8080))
except :
 print  datetime.datetime.now()


node1:/root/test#python a1.py 
2020-02-20 05:29:07.662334
34.0
2020-02-20 05:29:47.703091
node1:/root/test#


windows就不行:

socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])

转换 host/port 参数到 5元素元祖 

包含所有需要的参数用于创建一个socket连接到服务

hots 是一个domain名字,一个字符串形式的地址

port 是一个字符串服务名字 比如 http

The family, socktype and proto 参数是选择指定的 为了

缩小返回地址的列表。

默认,它们的值是0,意味着选择了整个结果范围。

socket.getfqdn([name])

返回一个完全限定的域名,如果名字是被省略或者为空

它解释为本地主机 为了查找完全限定名  gethostbyaddr() 返回的主机名是被检查

print socket.getfqdn()


TLCB-PC.zjtlcb.com


socket.gethostbyname(hostname)

转换一个主机名为IP4地址格式。 返回一个IPv4地址作为一个字符串

比如'100.50.200.5'  如果主机名是IPV4 地址本身 它返回不改变




print socket.gethostbyname('TLCB-PC')

192.168.8.57


socket.gethostbyname_ex(hostname)

转换一个主机名为IPV4地址格式 

print socket.gethostbyname_ex('TLCB-PC')


('TLCB-PC', [], ['192.168.8.57', '192.168.137.1'])

socket.gethostname()


返回一个字符串包含机器的主机名 

print socket.gethostname()

TLCB-PC

socket.gethostbyaddr(ip_address)

返回一个triple (hostname, aliaslist, ipaddrlist)  

主机名是主要的host name 回应对应的ip_address

print socket.gethostbyaddr('192.168.137.1')
('TLCB-PC.mshome.net', [], ['192.168.137.1'])

socket.getnameinfo(sockaddr, flags)

转换一个socket address 为一个2元素元祖

socket.getprotobyname(protocolname)

转换一个 Internet protocol name (for example, 'icmp') 为一个适用于传递作为第三个参数给socket()函数

print socket.getprotobyname('icmp')
1

print socket.getprotobyname('tcp')
6


socket.getservbyname(servicename[, protocolname])

转换一个Internet service 名字和协议名字为一个端口好 

可选的协议名字 
print socket.getservbyname('http','tcp')

80

socket.getservbyport(port[, protocolname])

转换一个internet 端口号和协议名字为一个服务名字 


print socket.getservbyport(80,'tcp')


http

socket.socket([family[, type[, proto]]])


创建一个新的socket 适用给定的地址,socket 类型,协议号等。

地址应该是AF_INET(默认的),AF_INET6 or AF_UNIX. 

socket 类型应该是SOCK_STREAM(默认)

SOCK_DGRAM 或者可能是其他constants 协议号通常是0  在这种情况下可以忽略

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


socket.socketpair([family[, type[, proto]]])

创建一对已连接的socket对象 适用给定的地址,socket type,


socket.fromfd(fd, family, type[, proto])



17.2.1. Socket Objects


Socket objects  有下面的方法, 它们对应于适用于套接字的Unix系统调用。

socket.accept()

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建套接字
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(ip_port)#绑定地址
s.listen(5)#监听链接
print('server listening8080...')
while True: #无限等待连接
    conn,addr = s.accept() #接受客户端连接
	

接收一个连接,socket 必须绑定到一个地址并且侦听连接。

返回值是一对(conn,addres) conn是一个新的socket 对象
<socket._socketobject object at 0x7fdaf2711a60>

conn 是一个新的socket对象 用于发送和接收数据,address 是

('192.168.137.1', 65028) 绑定到连接的对端

socket.bind(address)

绑定socket到地址,socket 不能是已经绑定的

s.bind(ip_port)#绑定地址

注意这个方法历史上只接收一对参数 而不是一个元祖 

socket.close()


关闭socket,所有的未来的操作在socket对象上都会失败


socket.connect(address)

s.connect(("192.168.137.2",8080))


连接到一个远程socket 

socket.connect_ex(address)

print s.connect_ex(("192.168.137.3",8080))
10060

print s.connect_ex(("192.168.137.2",8080))

0


socket.fileno()


返回socket的文件描述符(一个小的整数),这是有用的 对于select.select()

在Windows 下 小的整数通过这个方法返回 不能被使用 

print s.fileno()


352

socket.getpeername()


socket.getpeername()¶


返回远程地址 , 这个是有用的来找出 远程socket的端口好 

print s.getpeername()


('192.168.137.2', 8080)


socket.getsockname()


返回socket自己的地址 

print s.getsockname()


('192.168.137.1', 49581)


socket.getsockopt(level, optname[, buflen])

返回给定socket选项的值

socket.listen(backlog)

s.listen(5)#监听链接


侦听用于连接 backlog 参数指定最大的排队连接数 设置至少是0  


socket.makefile([mode[, bufsize]])

返回与套接字关联的文件对象

socket.recv(bufsize[, flags])

 msg = conn.recv(BUFSIZE) #接受消息的内容

从socket接受数据,返回值 是一个字符串代表接受的数据

  msg = conn.recv(BUFSIZE) #接受消息的内容
  if len(msg)==0:break  #如果 不加,已连接的客户端突然断开,recv不再阻塞>,发生死循环
  print msg

最大一次接收数据的总量是通过bufsize指定

socket.recvfrom(bufsize[, flags])

从socket 接收数据,返回的值是一个对(字符串,地址)

字符串是一个字符串表示接收到的数据,地址是发送数据的地址

socket.recv_into(buffer[, nbytes[, flags]])


从socket接收的字节数



socket.send(string[, flags])


s.send('this is shutdown test222')

发送数据到socket,socket 必须被连接到一个远程的socket

额外的flags 参数有相同的意思和recv()方法。

返回的是发送字节的长度 

如果数据的一部分被传输,应用需要尝试传递剩下的数据

socket.sendall(string[, flags])


print s.sendall("this is shutdown test11" + "\r\n")


发送数据到socket,socket必须连接到一个远程的socket.

额外的选项flags 参数有相同的意思和recv()方法

不像send(),这个方法继续发送数据从字符串直到所有的数据被发送 或者一个错误发生

成功是返回None

socket.sendto(string, flags, address)

发送数据到socket,socket 不应该被连接到一个远程socket.

socket.setblocking(flag)

设置blocking 和no-blocking 模式 如果flag是0,

socket 是设置为 non-blocking, 负责是blocking 模式,

最初所有的sockets 是在blocking模式, 

在非阻塞模式,如果一个recv() 调用不能找到任何数据, 或者如果一个send() 不能理解处理数据

一个异常抛出

在堵塞模式 请求堵塞知道它们可以处理.

 s.setblocking(0) is equivalent to s.settimeout(0.0); 非堵塞相当于立即超时
 
 堵塞相当于一直等待
 s.setblocking(1) is equivalent to s.settimeout(None).