使用套接字进行网络编程。python
使用socket
模块的socket()
函数,能够建立套接字。react
socket
模块函数要建立套接字,必须使用socket.socket()
函数,语法以下:shell
socket(socket_family, socket_type, protocol=0)
编程
其中,socket_family
是AF_UNIX
或AF_INET
,socket_type
是SOCK_STREAM
或SOCK_DGRAM
。protocol
一般省略,默认为0
。windows
导入模块缓存
建立TCP/IP
套接字安全
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
服务器
建立UDP/IP
套接字网络
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
框架
名称 | 描述 |
---|---|
s.bind() |
将地址(主机号、端口号对)绑定到套接字上 |
s.listen() |
设置并启动TCP 监听器 |
s.accept() |
被动接受TCP 客户端链接,一直等待知道链接到达(阻塞) |
名称 | 描述 |
---|---|
s.connect() |
主动发起TCP 服务器链接 |
s.connect_ex() |
connect() 的扩展版本,此时会以错误码的形式返回问题,而不是抛出一个异常 |
名称 | 描述 |
---|---|
s.recv() |
接收TCP消息 |
s.recv_into() |
接收TCP消息到指定的缓冲区 |
s.send() |
发送TCP消息 |
s.sendall() |
完整地发送TCP消息 |
s.recvfrom() |
接受UDP消息 |
s.recvfrom_into() |
接受UDP消息到指定的缓存区 |
s.sendto() |
发送UDP消息 |
s.getpeername() |
链接到套接字(TCP)的远程地址 |
s.getsockname() |
当前套接字的地址 |
s.getsockopt() |
返回给定套接字选项的指 |
s.setsockopt() |
设置给定套接字选项的值 |
s.shutdown() |
关闭链接 |
s.close() |
关闭套接字 |
s.detach() |
在未关闭文件描述符的状况下关闭套接字,返回文件描述符 |
s.ioctl() |
控制套接字的模式(仅支持windows) |
名称 | 描述 |
---|---|
s.setblocking() |
设置套接字的阻塞或非阻塞模式 |
s.settimeout() |
设置阻塞套接字操做的超时时间 |
s.gettimeout() |
获取阻塞套接字操做的超时时间 |
名称 | 描述 |
---|---|
s.fileno() |
套接字的文件描述符 |
s.makefile() |
建立与套接字关联的文件对象 |
名称 | 描述 |
---|---|
s.family |
套接字家族 |
s.type |
套接字类型 |
s.proto |
套接字协议 |
TCP服务器的通常伪代码。
ss = socket() # 建立服务器套接字 ss.bind() # 套接字与地址绑定 ss.listen() # 监听链接 inf_loop: # 服务器无限循环 cs = ss.accept() # 接收客户端链接 comm_loop: # 通讯循环 cs.recv() / cs.send() # 对话(接受/发送) cs.close() # 关闭客户端套接字 ss.close() # 关闭服务器套接字(可选)
socket.socket()
函数来建立accept()
函数以后,就开启了一个简单的服务器,它会等待客户端的链接,默认状况下,accept()
是阻塞的,这意味着执行将被暂停,直到一个链接到达accept()
)一个独立的客户端套接字,用来与即将到来的消息进行交换下面是一个TCP服务器程序,它接受客户端发送的数据字符串,并将其打上时间戳,并返回给客户端。
# coding: utf-8 from socket import * from time import ctime HOST = '' # HOST变量是空白,这是对bind()方法的标识,表示它能够使用任何可用的地址 PORT = 21567 BUFSIZ = 1024 # 缓冲区大小设置为1KB ADDR = (HOST, PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) # 分配TCP服务器套接字 tcpSerSock.bind(ADDR) # 将套接字绑定到服务器地址 tcpSerSock.listen(5) # 开启TCP监听器的调用,参数是在链接被转接或拒绝以前,传入链接请求的最大数 while True: print('waiting for connection...') tcpCliSock, addr = tcpSerSock.accept() # 被动等待客户端的链接 print('...connected from:', addr) while True: data = tcpCliSock.recv(BUFSIZ) # 等待客户端发送的消息 if not data: # 若是消息是空白的,意味着客户端已经退出 break # 跳出对话循环 tcpCliSock.send(bytes('[%s] %s' % (ctime(), data), 'utf-8')) tcpCliSock.close() # 关闭当前客户端链接 # tcpSerSock.close()
TCP客户端的通常伪代码。
cs = socket() # 建立客户端套接字 cs.connect() # 尝试链接服务器 comm_loop: # 通讯循环 cs.send() / cs.recv() # 对话(发送 / 接受) cs.close() # 关闭客户端套接字
Python代码实现的TCP客户端。
# coding: utf-8 from socket import * HOST = '127.0.0.1' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) # 分配TCP客户端套接字 tcpCliSock.connect(ADDR) # 主动调用并链接到服务器 while True: data = input('> ') if not data: break tcpCliSock.send(bytes(data, 'utf-8')) data = tcpCliSock.recv(BUFSIZ) if not data: break print(data.decode('utf-8')) tcpCliSock.close()
服务器端
bovenson@ThinkCentre:~/Git/notes/Python/Code/LearnPythonCode/network_programming$ python3 tsTserv.py waiting for connection... ...connected from: ('127.0.0.1', 35550)
客户端
bovenson@ThinkCentre:~/Git/notes/Python/Code/LearnPythonCode/network_programming$ python3 tsTclnt.py > Hello [Mon Jun 4 11:20:46 2018] b'Hello' > World [Mon Jun 4 11:20:48 2018] b'World' >
UDP服务器不须要TCP服务器那么多的设置,由于它们不是面向链接的,除了等待传入的链接以外,几乎不须要作其余工做。
ss = socket() # 建立服务器套接字 ss.bind() # 绑定服务器套接字 inf_loop(): # 服务器无限循环 cs = ss.recvfrom() / ss.sendto() # 关闭(接受 / 发送) ss.close() # 关闭服务器套接字
UDP服务器和TCP服务器之间的另外一个显著差别是,觉得数据报套接字是无链接的,因此就没有为了成功通讯而使一个客户端链接到一个独立的套接字转换操做。这些服务器仅仅接受消息并有可能回复数据。
# coding: utf-8 from socket import * from time import ctime HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) udpSerSock = socket(AF_INET, SOCK_DGRAM) udpSerSock.bind(ADDR) while True: print('waiting for message...') data, addr = udpSerSock.recvfrom(BUFSIZ) udpSerSock.sendto('[%s] %s' % (ctime(), data), addr) print('...received from and returned to:', addr) # udpSerSock.close()
客户端伪代码以下。
ss = socket() # 建立客户端套接字 comm_loop: # 通讯循环 cs.sendto() / cs.recvfrom() # 对话(发送 / 接收) cs.close() # 关闭客户端套接字
Python实现的客户端代码。
# coding: utf-8 from socket import * from time import ctime HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) udpSerSock = socket(AF_INET, SOCK_DGRAM) udpSerSock.bind(ADDR) while True: print('waiting for message...') data, addr = udpSerSock.recvfrom(BUFSIZ) udpSerSock.sendto(bytes('[%s] %s' % (ctime(), data), 'utf-8'), addr) print('...received from and returned to:', addr) # udpSerSock.close()
客户端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsUclnt.py > Hello b"[Mon Jun 4 12:42:07 2018] b'Hello'" > World b"[Mon Jun 4 12:42:08 2018] b'World'" >
服务端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsUserv.py waiting for message... ...received from and returned to: ('127.0.0.1', 59736) waiting for message... ...received from and returned to: ('127.0.0.1', 59736) waiting for message...
注 和TCP不一样的是,UDP客户端能够先于UDP服务器运行。可是TCP服务器必须先于TCP客户端运行。
socket
模块属性属性名称 | 描述 |
---|---|
AF_UNIX,AF_INET,AF_INET6,AF_NETLINK,AF_TIPC |
Python 中支持的套接字地址家族 |
SO_STREAM,SO_DGRAM |
套接字类型(TCP=流,UDP=数据报) |
has_ipv6 |
指示是否支持IPv6 的布尔标记 |
名称 | 描述 |
---|---|
error |
套接字相关错误 |
herror |
主机和地址相关错误 |
gaierror |
地址相关错误 |
timeout |
超时时间 |
名称 | 描述 |
---|---|
socket() |
以给定的地址家族、套接字类型和协议类型(可选)建立一个套接字对象 |
socketpair() |
以给定的地址家族、套接字类型和协议类型(可选)建立一对套接字对象 |
create_connection() |
常规函数,接受一个地址(主机号,端口号)对,返回套接字对象 |
fromfd() |
以一个打开的文件描述符建立一个套接字对象 |
ssl() |
经过套接字启动一个安全套接字层链接;不执行证书验证 |
getaddrinfo() |
获取一个五元组序列形式的地址信息 |
getnameinfo() |
给定一个套接字地址,返回(主机号,端口号)二元组 |
getfqn() |
返回完整的域名 |
gethostname() |
返回当前主机名 |
gethostbyname() |
将一个主机名映射到它的IP地址 |
gethostbyname_ex() |
gethostname() 的扩展版本,它返回主机名、别名主机集合和IP地址列表 |
gethostbyaddr() |
将一个IP地址映射到DNS信息:返回与gethostbyname_ex() 相同的3元组 |
getprotobyname() |
将一个协议名(如tcp )映射到一个数字 |
getservbyname()/getservbyport() |
将一个服务名映射到一个端口号,或者反过来;对于任何一个函数来讲,协议名都是可选的 |
ntohl()/ntohs() |
未来自网络的整数转换为主机字节顺序 |
htonl()/htons() |
未来自主机的整数转换为网络字节顺序 |
inet_aton()/inet_ntoa() |
将IP地址八进制字符串转换为32位的包格式,或者反过来(仅用于IPv4地址) |
inet_pton()/inet_ntop() |
将IP地址字符串转换成打包的二进制格式,或者反过来(同时适用于IPv4和IPv6地址) |
getdefaulttimeout()/setdefaulttimeout() |
以秒(浮点数)为单位返回默认套接字超时时间;以秒(浮点数)为单位设置默认套接字超时时间 |
SocketServer
模块SocketServer
是标准库中的一个高级模块,它的目标是简化不少样板代码,它们是建立网络客户端和服务器所需必须的代码。
类 | 描述 |
---|---|
BaseServer |
包含核心服务器功能和mix-in 类的钩子;仅用于推导,这样不会建立这个类的实例;能够用TCPServer 和UDPServer 建立类的实例 |
TCPServer/UDPServer |
基础的网络同步TCP/UDP 服务器 |
UnixStreamServer/UnixDatagramServer |
基于文件的基础同步TCP/UDP 服务器 |
ForkingMixIn/ThreadingMixIn |
核心派出或线程功能;只用做mix-in 类与一个服务器类配合实现一些异步性;不能直接实例化这个类 |
ForkingTCPServer/ForkingUDPServer |
ForkingMixIn 和TCPServer/UDPServer 的组合 |
ThreadingTCPServer/ThreadingUDPServer |
ThreadingMixIn 和TCPServer/UDPServer 的组合 |
BaseRequestHandler |
包含处理服务请求的核心功能;仅仅用于推导,这样没法建立这个类的实例;能够使用StreamRequestHandler 或DatagramRequestHandler 建立类的实例 |
StreamRequestHandler/DatagramRequestHandler |
实现TCP/UDP 服务器的服务处理器 |
事件包括消息的发送和接受。
类定义只包括一个用来接收客户端消息的事件处理程序,全部其余的功能都来自使用的SocketServer
类。
SocketServer
TCP服务器# coding: utf-8 from socketserver import (TCPServer as TCP, StreamRequestHandler as SRH) from time import ctime HOST = '' PORT = 21567 ADDR = (HOST, PORT) class MyRequestHandler(SRH): def handle(self): print('...connected from:', self.client_address) self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline())) tcpServ = TCP(ADDR, MyRequestHandler) print('waiting for connection...') tcpServ.serve_forever()
MyRequestHandler
做为SocketServer
中StreamRequestHandler
的一个子类,并重写了它的handler()
方法。当接收到一个来自客户端的消息时,就会调用handler()
方法。而StreamRequestHandler
类将输入和输出套接字看做相似文件的对象,所以咱们将使用readline()
来获取客户端消息,并利用write()
将字符串发送回客户端。
SocketServer
TCP客户端# coding: utf-8 from socket import * HOST = 'localhost' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) data = input('> ') if not data: break tcpCliSock.send(bytes('%s\r\n' % data, 'utf-8')) data = tcpCliSock.recv(BUFSIZ) if not data: break print(data.strip()) tcpCliSock.close()
服务端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTservSS.py waiting for connection... ...connected from: ('127.0.0.1', 36118) ...connected from: ('127.0.0.1', 36120) ...connected from: ('127.0.0.1', 36122)
客户端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTclntSS.py > a b"[Mon Jun 4 15:34:12 2018] b'a\\r\\n'" > c b"[Mon Jun 4 15:34:13 2018] b'c\\r\\n'" >
Twisted
是一个完整的事件驱动的网络框架,既能够使用,也能开发完整的异步网络应用程序和协议。
Twisted Reactor
TCP服务器# coding: utf-8 from twisted.internet import protocol, reactor from time import ctime PORT = 21567 class TSServProtocol(protocol.Protocol): def connectionMade(self): # 客户端链接到服务器时就会执行 clnt = self.clnt = self.transport.getPeer().host print('...connected from:', clnt) def dataReceived(self, data): # 当服务器收到客户端经过网络发送的一些数据时就会调用 dataReceived() 方法 self.transport.write(bytes('[%s] %s' % (ctime(), data), 'utf-8')) factory = protocol.Factory() factory.protocol = TSServProtocol print('waiting for connection...') reactor.listenTCP(PORT, factory) reactor.run()
Twisted Reactor
TCP客户端# coding: utf-8 from twisted.internet import protocol, reactor HOST = 'localhost' PORT = 21567 class TSClntProtocol(protocol.Protocol): def sendData(self): data = input('> ') if data: print('...sending %s...' % data) self.transport.write(bytes(data, 'utf-8')) else: self.transport.loseConnection() def connectionMade(self): self.sendData() def dataReceived(self, data): print(data) self.sendData() class TSClntFactory(protocol.ClientFactory): protocol = TSClntProtocol clientConnectionLost = clientConnectionFailed = lambda self, connector, reason: reactor.stop() reactor.connectTCP(HOST, PORT, TSClntFactory()) reactor.run()
服务器
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTservTW.py waiting for connection... ...connected from: 127.0.0.1
客户端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTclntTW.py > a ...sending a... b"[Mon Jun 4 16:40:40 2018] b'a'" > b ...sending b... b"[Mon Jun 4 16:40:42 2018] b'b'" >