Socket通信¶
概要¶
socket几乎是整个网络通信的基础,本文为大家讲解Micropython中的Socket模块。
socket模块 API文档¶
宏¶
socket
模块中定义了许多和协议相关的宏,笔者整理出了下表:
宏定义名称 | 值(int) | 功能 | 含义 |
---|---|---|---|
socket.AF_INET |
2 | 地址簇 | TCP/IP – IPv4 |
socket.AF_INET |
10 | 地址簇 | TCP/IP - IPv6 |
socket.SOCK_STREAM |
1 | 套接字类型 | TCP流 |
socket.SOCK_DGRAM |
2 | 套接字类型 | UDP数据报 |
socket.SOCK_RAW |
3 | 套接字类型 | 原始套接字 |
socket.SO_REUSEADDR |
4 | 套接字类型 | socket可重用 |
socket.IPPROTO_TCP |
16 | IP协议号 | TCP协议 |
socket.IPPROTO_UDP |
17 | IP协议号 | UDP协议 |
socket.SOL_SOCKET |
4095 | 套接字选项级别 |
函数¶
socket.getaddrinfo(host, port)¶
函数说明:将主机域名(host)和端口(port)转换为用于创建套接字的5元组序列。元组列表的结构如下:
(family, type, proto, canonname, sockaddr)
示例:
>>> info = socket.getaddrinfo("127.0.0.1", 10000) >>> print(info) [(2, 1, 0, '127.0.0.1', ('127.0.0.1', 10000))]
socket.socket([af, type, proto])¶
函数说明:创建套接字。
-
af
:地址 -
type
:类型 -
proto
:协议号
*注意: 一般不指定proto参数,因为有些Micropython固件提供默认参数。 *
示例:
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> print(s) <socket>
socket.socket.setsockopt(level, optname, value)¶
函数说明:根据选项值设置套接字。
-
level
:套接字选项级别 -
optname
:套接字的选项 -
value
:可以是一个整数,也可以是一个表示缓冲区的bytes类对象。
示例:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
socket.socket.bind(address)¶
函数说明:以列表或元组的方式绑定地址和端口号。
address
:一个包含地址和端口号的列表或元组。
示例:
addr = ("127.0.0.1",10000) s.bind(addr)
socket.socket.listen([backlog])¶
函数说明:监听套接字,使服务器能够接收连接。
backlog
:接受套接字的最大个数,至少为0,如果没有指定,则默认一个合理值。
socket.socket.accept()¶
函数说明:接收连接请求。
注意:只能在绑定地址端口号和监听后调用,返回conn和address。
-
conn:新的套接字对象,可以用来收发消息
-
address:连接到服务器的客户端地址
示例:
conn,addr = s.accept()
socket.socket.connect(address)¶
函数说明:连接服务器。
- address:服务器地址和端口号的元组或列表
示例:
host = "192.168.3.147" port = 100 s.connect((host, port))
socket.socket.send(bytes)¶
函数说明:发送数据,并返回发送的字节数。
- bytes:bytes类型数据
示例:
s.send("hello 1ZLAB, I am TCP Client")
socket.socket.sendall(bytes)¶
函数说明:与send()函数类似,区别是sendall()函数通过数据块连续发送数据。
- bytes:bytes类型数据
示例:
s.sendall("hello 1ZLAB, I am TCP Client")
socket.socket.sendto(bytes, address)¶
函数说明:发送数据,目标由address决定,用于UDP通信,返回发送的数据大小。
-
bytes:bytes类型数据
-
address:目标地址和端口号的元组
示例:
data = sendto("hello 1ZLAB", ("192.168.3.147", 100))
socket.socket.recv(bufsize)¶
函数说明:接收数据,返回接收到的数据对象。
- bufsize:指定一次接收的最大数据量
示例:
data = conn.recv(1024)
socket.socket.recvfrom(bufsize)¶
函数说明:接收数据,用于UDP通信,并返回接收到的数据对象和对象的地址。
- bufsize:指定一次接收的最大数据量
示例:
data,addr=fd.recvfrom(1024)
socket.socket.settimeout(value)¶
函数说明:设置超时时间,单位:秒。
示例:
s.settimeout(2)
socket.socket.readline()¶
函数说明:接收一行数据,遇换行符结束,并返回接收数据的对象 。
socket.socket.write(buf)¶
函数说明:将字节类型数据写入套接字,并返回写入数据的大小。
socket.socket.close()¶
函数说明:关闭套接字。
示例:
s.close()
TCP服务端和客户端通信示例¶
确保你的ESP32和你的PC在同一局域网内。
在接下来的示例中,我们以ESP32建立TCP服务端,在PC上编写脚本 创建TCP客户端,与服务器进行通信。
ESP32 TCP服务端¶
""" ESP32 TCP Server """ import socket from emp_wifi import Wifi port = 10000 #端口号 listenSocket = None #套接字 try: # 注意:线连接到WiFi网络! # 如果未连接到网络,以下是连接到网络的代码 # Wifi.connect() ip = Wifi.ifconfig()[0][0] #获取IP地址 listenSocket = socket.socket() #创建套接字 listenSocket.bind((ip, port)) #绑定地址和端口号 listenSocket.listen(1) #监听套接字, 最多允许一个连接 listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #设置套接字 print ('tcp waiting...') while True: print("accepting.....") conn, addr = listenSocket.accept() #接收连接请求,返回收发数据的套接字对象和客户端地址 print(addr, "connected") while True: data = conn.recv(1024) #接收数据(1024字节大小) if(len(data) == 0): #判断客户端是否断开连接 print("close socket") conn.close() #关闭套接字 break print(data) ret = conn.send(data) #发送数据 except: if(listenSocket): #判断套接字是否为空 listenSocket.close() #关闭套接字
PC TCP客户端¶
# -*- coding: UTF-8 -*- # PC TCP Client import socket # 导入 socket 模块 s = socket.socket() # 创建 socket 对象 host = '192.168.2.231' # esp32 ip port = 10000 # 设置端口号 s.connect((host, port)) if __name__ == '__main__': while True: msg = raw_input('>>> ') s.send(msg)
收看星球大战字符动画¶
blinkenlights.nl网站提供的星球大战Asciimation服务。它使用端口23上的telnet协议将数据流式传输给任何连接的人。
接下来,让我们建立一个TCP通信,在我们的REPL中观看星球大战。
首先要导入套接字模块:
>>> import socket
然后我们通过域名来获取服务器的地址
>>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)
getaddrinfo
函数实际上返回一个地址列表:
[(2, 1, 0, 'towel.blinkenlights.nl', ('94.142.241.111', 23))]
我们只需要获取服务器的IP地址和端口,对应于该列表第一项的最后一个元组:
>>> addr = addr_info[0][-1]
建立一个socket对象,然后使用上面的IP地址和端口号与服务器进行连接:
>>> s = socket.socket() >>> s.connect(addr)
现在我们已经连接,我们可以获取并显示数据了:
>>> while True: ... data = s.recv(500) ... print(str(data, 'utf8'), end='') ...
当这个循环执行时,它应该开始显示动画(使用ctrl-C来中断它)
思考¶
如何使用 Socket通信,来远程点亮ESP32控制的LED呢?你将制定何种通信协议呢?