操作文件和 socket 编程在平时也是必不可少的,这里介绍了 Python3 相关内容,做一个备忘。
网络编程
socket 编程
-
Linux 中的 socket :
- socket 也叫做套接字,起源于Unix,是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口;
- socket 中没有层的概念,它只是一个 facade 设计模式(门面模式)的应用,它把复杂的 TCP/IP 协议族隐藏在 socket 接口后面;对用户来说,一组简单的接口就是全部,让 socket 去组织数据,以符合指定的协议,而不需要让用户自己去定义什么时候需要指定哪个协议哪个函数;
-
socket 都可以用
open() –> write/read –> close()
模式来操作,socket 即是一种特殊的文件,一些 socket 函数就是对其进行的操作(读/写IO、打开、关闭); - 在网络编程中,我们大量用的都是通过socket实现的。
-
Python 中 socket 函数接口相关:
- AF_UNIX 代表本地通讯套接字
- AF_INET 代表 IPV4 网络套接字
- SOCK_STREAM 代表基于连接的数据传输,类比 TCP
- SOCK_DGRAM 代表不基于连接,基于报文的数据传输,类比 UDP
-
bind()
绑定地址时,在 AF_UNIX 下是文件名的形式,在 AF_INET 下是(host,port)的形式 -
listen()
开始监听绑定的地址,参数含义:在拒绝连接之前,可以挂起的最大连接数量 -
send()
发送数据 -
recv()
接收数据
-
C/S 模型示例
# Server 端
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # 创建套接字对象
sockName = "/tmp/UNIX.motion.server.d"
if os.path.exists(sockName):
os.unlink(sockName)
s.bind(sockName) # 绑定地址
s.listen(5) # 开始监听
conn, address = s.accept() # 被动接受客户端连接,阻塞式等待连接的到来
data = 'hello world'
conn.send(bytes(data, "utf-8")) # 数据交换
conn.close()
s.close()
# Client 端
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # 创建套接字对象
s.connect("/tmp/UNIX.motion.server.d") # 发送连接请求
data = s.recv(500) # 数据交换
s.close()
SSL(Secure Sockets Layer 安全套接层)
- python 标准库 ssl 可实现加密通信
- ssl 库底层使用 openssl,做了面向对像化改造和简化,但还是可以明显看出 openssl 的痕迹
- 说到 ssl 很多人都会想到https,但本质而言 ssl 是在传输层和应用层之间新插入的一个层,根据不同层无关原则 ssl 和 https 并没有任何绑定关系,ssl 之上完全可以是其他任何应用层协议
- 应用实例
## 服务端
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) # 生成 SSL 上下文
context.load_cert_chain('cert/server.crt', 'cert/server_rsa_private.pem.unsecure') # 加载服务器所用证书和私钥
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock: # 监听端口
sock.bind(('127.0.0.1', 9443))
sock.listen(5)
# 将 socket 打包成 SSL socket
with context.wrap_socket(sock, server_side=True) as ssock:
while True:
# 接收客户端连接
client_socket, addr = ssock.accept()
# 接收客户端信息
msg = client_socket.recv(1024).decode("utf-8")
print(f"receive msg from client {addr}:{msg}")
# 向客户端发送信息
msg = f"yes , you have client_socketect with server.\r\n".encode("utf-8")
client_socket.send(msg)
client_socket.close()
## 客户端
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # 生成 SSL 上下文
context.load_verify_locations('cert/ca.crt') # 加载信任根证书
with socket.create_connection(('127.0.0.1', 9443)) as sock: # 与服务端建立 socket 连接
# 将 socket 打包成 SSL socket
# 一定要注意的是这里的server_hostname不是指服务端IP,而是指服务端证书中设置的CN
with context.wrap_socket(sock, server_hostname='127.0.0.1') as ssock:
# 向服务端发送信息
msg = "do i connect with server ?".encode("utf-8")
ssock.send(msg)
# 接收服务端返回的信息
msg = ssock.recv(1024).decode("utf-8")
print(f"receive msg from server : {msg}")
ssock.close()
文件和 I/O
本文只讨论 Python 的文件和流操作,不讨论系统相关的目录操作。
文件操作常用函数
-
open()
,打开文件,文件指针的位置和打开时的读写模式有关 -
.close()
,关闭文件,释放文件句柄,建议使用
with
操作 -
.write()
,以当前文件指针,向文件写数据 -
.read()
,以当前文件指针,从文件读数据 -
.readline()
,以当前文件指针,从文件读一行文本 -
.tell()
,显示当前指针位置 -
.seek()
,移动指针位置
文件打开读写模式
-
w
以写方式打开 -
W
文件若存在,首先要清空,然后(重新)创建 -
a
以追加模式打开 (从 EOF 开始, 必要时创建新文件) -
r+
以读写模式打开
1. 文件存在,打开文件,文件指针定位到
文件开始位置
2. 文件不存在, 则报错文件不存在。 -
w+
以写读模式打开 (参见 w )
1. 文件存在,则
清空
(也即写入空);
2. 文件不存在,则创建文件 ;
3. 文件流定位到开始位置, 所以read() 会得到空。 -
a+
以读写模式打开 (参见 a )
1. 文件存在,打开文件,文件指针定位到文件开始位置,但不清空;
2. 文件不存在,创建文件;
3. 打开后读取时,在文件开头位置,
4. 写入时,添加到文章末尾,并且指针位于添加后的末尾,所以再次读取会乱码。 -
rb
以二进制读模式打开 -
wb
以二进制写模式打开 (参见 w ) -
ab
以二进制追加模式打开 (参见 a ) -
rb+
以二进制读写模式打开 (参见 r+ ) -
wb+
以二进制读写模式打开 (参见 w+ ) -
ab+
以二进制读写模式打开 (参见 a+ ) -
另外:
1.
w
打开文件写入,也会清空文件,如果使用read(),则报错;a 打开文件添加,数据流添加到文件末尾,而不是w模式的清空后,添加到文件末尾。
2.
b
可以附加到上述的字母后,形成
rb
,
rb+
,
wb
等等模式,针对二进制文件,比如exe, elf, jpeg格式的文件,进行文件操作; 在unix 类型的系统上,text格式与二进制的处理相同,但是非unix类型的系统上,换行格式不同,所以需要用加b模式来在指定是否是二进制。-
并发读文件时
,偶尔会因为读不到(其实有数据)数据而返回 ‘’ 空串,应该是因为句柄被占用了。
-
I/O 流操作
io 模块提供了 Python 用于处理各种 I/O 类型的主要工具。三种主要的 I/O 类型分别为: 文本 I/O, 二进制 I/O 和原始 I/O。这些是泛型类型,有很多种后端存储可以用在他们上面。一个隶属于任何这些类型的具 体对象被称作 file object。其他同类的术语还有 流和 类文件对象。
- Text I/O 用于识别和处理字符串你对象。
- Binary I/O 也称作缓冲流,以字节为对象操作数据。
- Raw I/O 也称作非缓冲流,用于低级别的的二进制流操作。
参考文档
版权声明:本文为ManWZD原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。