涉及到在内存中存在数据叫喊的操作。
** Io密集型程序** Io密集型程序指的是在程序执行过程中,有大量的Io操作,而cpu运算较少。耗时cpu较少,但花费时间; 计算密集型程序 计算密集型程序,指的是程序中的计算量较大,IO操作相对较少,cpu消耗大,执行熟读快,几乎没有阻塞。 文件 文件是保存在持久化储存设备上的一段数据。它从格式上可以分为:文本文件,二进制文件等。在python中见文件看作是一种类型的对象,类似其他类型。 字节串 字节串的概念是在python3中才引入的。与字符串不同的是:字节串使用直接序列值表示数据。是常见的二进制数据展现形式。
对文件的操作有:打开文件,读写文件和关闭文件。 打开文件:
#buffering 1 表示有行缓冲,成功返回文件操作对象 file_object = open(filename,access_bode='打开类型:r,w,a等',buffering=-1)r 以读方式打开 文件必须存在 w 以写方式打开,文件不存在则创建,存在清空原有内容。 a 以追加模式打开 r+ 以读写模式打开 文件必须存在 w+ 以读写模式打开文件,不存在则创建,存在清空原有内容。 a+ 以读写模式打开 追加模式 rb 以二进制读模式打开 同r wb 以二进制写模式打开 同w ab 以二进制追加模式打开 同a rb+ 以二进制读写模式打开 同r+ wb+ 以二进制读写模式打开 同w+ ab+ 以二进制读写模式打开 同a+
读取文件
读取文件的方式有: read([size]):
data=f.read(16) # [size]:当给定时,表示读取到给定数目的字符或者字节;当不给定,或者为负数的时候,文件将被读取到文件结尾。readline([size]): 用来读取文件中一行,
data=f.readlin(28) #[size]:如果没有给定size参数(默认值为-1)或者size值为负,表示读取一行;给定size,它和read()没有区别。readlines([sizeint]):
data = f.readlines([]) #读取文件中的每一行作为列表中的一项;当不给sizeint时,和read()一样;当给定sizeint,读取到size字符所在的行为止。参考代码
# 打开文件 f = open('1.jpg','rb') # 读操作 while True: # 到文件结尾时会读出空字串 data = f.read(16) # 到文件结尾跳出循环 if not data: break print("读取到的数据:",data) # 每次读取一行内容 data = f.readline(6) print("一行内容:",data) data = f.readline() print("一行内容:",data) print("**************************************") # 将内容读取到一个列表 # 参数表达的是读取到该字符数所在的行 data = f.readlines(28) print(data) # 文件对象可迭代,每次一行 for line in f: print(line) # 关闭 f.close()文件的写入 写入文件的方式有:
write(string): 功能: 把文本数据或二进制数据块的字符串写入到文件中去 参数:要写入的内容 返回值:写入的字符个数
writelines(str_list): 功能:接受一个字符串列表作为参数,将它们写入文件。 参数: 要写入的内容列表
f = open('text','w') f.write(b"hello,diegui\n") # 如果希望换行则自己添加 m = open('text','ab') m.write("哎呀,干啥".encode()) # 写入列表内容 l = ['hello world\n','哈哈哈\n'] f.writelines(l)with操作 保证不管处理过程中是否发生错误或者异常都会执 行规定的“清理”操作,释放被访问的资源,比如有文件读写后自动关闭、线程中锁的自动获取和释放 等。 举例:
with open('4.txt') as f: # 以只读方式生成f对象 data = f.read() print(data)通过with方法可以不用close(),因为with生成的对象在语句块结束后会自动处理,所以也就不需要close 了,但是这个文件对象只能在with语句块内使用。
刷新缓冲区 刷新缓冲区条件:
缓冲区被写满
程序执行结束或者文件对象被关闭
行缓冲遇到换行
程序中调用flush()函数
flush() 该函数调用后会进行一次磁盘交互,将缓冲区中的内容写入到磁盘。 举例:
f = open('test','w') while True: data = input(">>") if not data: break f.write(data + '\n') f.flush() # 主动刷新缓冲 f.close()文件偏移量 功能:移动文件偏移量位置 参数:offset 代表相对于某个位置移动的字节数。负数表示向前移动,正数表示向后移动。 whence是基准位置的默认值为 0,代表从文件开头算起,1代表从当前位置算起,2 代表从文件末 尾算起。 举例:
f = open("test",'wb+') f.write(b"Hello world") print("偏移量:",f.tell()) # 获取文件偏移量 f.seek(-5,2) # 将文件偏移量定位到开头 data = f.read() print(data) f.close()系统中每一个IO操作都会分配一个整数作为编号,该整数即这个IO操作的文件描述符。 可以通过:fileno() 通过IO对象获取对应的文件描述符。 文件管理函数
获取文件大小 os.path.getsize(file)查看文件列表 os.listdir(dir)查看文件是否存在 os.path.exists(file)判断文件类型 os.path.isfile(file)删除文件 os.remove(file)计算机网络功能主要实现资源共享,数据信息的传递。
应用层: 提供用户服务,具体功能应用程序。 表示层: 数据的压缩优化加密。 会话层: 建立用户级的连接,选择适当的传输服务。 传输层: 提供传输服务。 网络层: 路由选择,网络互联。 数据链路层: 进行数据的交互,控制具体数据发送。 物理层: 提供数据传输的硬件保证,网卡接口,传输介质。
应用层: ( 应用层[TFTP,FTP,NFS,WAIS,HTTP],表示层[Telnet,Rlogin,SNMP,Gopher],会话层[SMTP,DNS])。 传输层: (传输层:[tcp,udp])。 网际层: (网络层:[IP,ICMP,ARP,RARP,AKP,UUCP])。 网络接口: (数据链路层[FDDI,Ethernet,Arpanet,PDN,SLTP,PPP],物理层[硬件设备等])。 ![全双工的面向连接的可靠的按序递交的无重复的字节流通信]
传输层服务:
面向链接的传输层服务(基于TCP协议的数据传输)
传输特征:提供可靠的数据传输,在传输过程中,无丢失,无失序,无差错,无重复。 实现手段:在通信前建立数据链接,通信结束要正常断开连接。
三次握手(建立连接): 客户端向服务端发送消息保温的请求连接(SYN=1,Seq=X); 服务器收到请求后,回复保温确定可以连接(SYN=1,ACK=X+1,Sep=Y); 客户端收到回复,发送最终报文连接(ACK=Y+1,Seq=Z)。 四次挥手(断开连接): 主动方发送报文请求断开连接(Fin=1,AcK=Z,Seq=X); 被动方收到请求,立即回复,表示准备断开(ACK=X+1,Seq=Z); 被动方准备就绪,再次发送报文表示可以断开连接(Fin=1,AcK=X,Seq=Y); 主动方收到确定,发送最终报文完成断开(ACK=Y Seq=X)。 创建过程,及代码实现:
服务端代码:
import socket # 创建tcp套接字对象 sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定地址 sockfd.bind(('0.0.0.0',9999)) # 设置监听 sockfd.listen(5) # 等待处理客户端连接请求 print("Waiting for connect...") connfd,addr = sockfd.accept() print("Connect from",addr) # 消息收发 data = connfd.recv(1024) print("Receive:",data.decode()) n = connfd.send(b"Thanks") print('Send %d bytes'%n) # 关闭套接字 connfd.close() sockfd.close()客户端代码(配合服务端使用):
from socket import * # 创建tcp套接字 sockfd = socket() # 默认值 # 连接服务器 server_addr = ('127.0.0.1',9999) # 服务器地址 sockfd.connect(server_addr) # 先发后收 msg = input("Msg:") sockfd.send(msg.encode()) #字节串 data = sockfd.recv(1024) print("From server:",data.decode()) sockfd.close()面向无连接的传输层服务(基于UDP协议的数据传输)
传输特点 : 传输过程没有连接和断开,数据收发自由随意。适用情况 : 网络较差,对传输可靠性要求不高。比如:网络视频,群聊,广播udp服务端代码:
from socket import * # 创建udp套接字 sockfd = socket(AF_INET,SOCK_DGRAM) # 绑定地址 server_addr = ('127.0.0.1',8888) sockfd.bind(server_addr) # 循环收发消息 while True: data,addr = sockfd.recvfrom(1024) print("Msg from %s: %s"%(addr,data.decode())) sockfd.sendto(b'Thanks',addr) # 关闭套接字 sockfd.close()udp客户端实现代码:
from socket import * # 服务器地址 ADDR = ("127.0.0.1",8888) # 创建套接字 sockfd = socket(AF_INET,SOCK_DGRAM) # 循环收发消息 while True: data = input("Msg>>") if not data: # 退出 break sockfd.sendto(data.encode(),ADDR) msg,addr = sockfd.recvfrom(1024) print("From server:",msg.decode()) sockfd.close()由上面的代码,你也已经对套接字**(socket)**有了一定的感性认识: 那么下面,我将详细阐述有关的问题。
服务端:
1.创建套接字:
# 创建tcp套接字对象 sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)2.绑定地址:
# 绑定地址 sockfd.bind(('0.0.0.0',9999))3.设置监听:
# 设置监听 sockfd.listen(5)4.等待处理客户端链接请求: 我们在这里用一个举例进行说明
# 等待处理客户端连接请求 while True: print("Waiting for connect...") try: connfd,addr = sockfd.accept() print("Connect from",addr) except KeyboardInterrupt: # ctrl-c 退出程序 print("Server exit") break except Exception as e: print(e) continue其中使用到了:
connfd,addr = sockfd.accept() #功能: 阻塞等待处理客户端请求返回值: connfd 客户端连接套接字addr 连接的客户端地址5.收发消息:
# 消息收发 (先收后发) while True: data = connfd.recv(1024) #消息接收 # 如果data为空意味着客户端断开 if not data: break print("Receive:",data.decode()) # if data == b'Q': # break n = connfd.send(b"Thanks") #消息发送 print('Send %d bytes'%n) connfd.close()6.关闭套接字:
sockfd.close() #功能:关闭套接字客户端 1.创建套接字:
from socket import * # 创建tcp套接字 sockfd = socket() # 默认值2.链接服务器:
# 连接服务器 server_addr = ('127.0.0.1',9999) # 服务器地址 sockfd.connect(server_addr)3.收发消息:
# 先发后收 while True: msg = input("Msg:") if not msg: break sockfd.send(msg.encode()) #字节串 # if msg == 'Q': # break data = sockfd.recv(1024) print("From server:",data.decode())这里要注意一点:服务端和客户端的收发消息的次序刚好是反过来的,一端先发后收,另一端必须是先收后发。
4.关闭套接字:
sockfd.close()tcp套接字数据传输的特点: 当一端退出,另一端会阻塞在recv,此时recv会立即返回一个空字符串; tcp链接中如果一端已经不存在,仍然进行send 会出现BrokenPipError; 一个监听套接字可以同时连接多个客户端,也能够重复被连接. tcp粘包: tcp以字节流方式传输,没有消息边界。多次发送的消息被一次接收,此时就会形成粘包; 可以通过设置发送速度进行控制,或者人为设置消息边界。
tcp套接字和udp套接字编程区别:
流式套接字是以字节流方式传输数据,数据报套接字以数据报形式传输;tcp套接字会有粘包,udp套接字有消息边界不会粘包;tcp套接字保证消息的完整性,udp套接字则不能;tcp套接字依赖listen accept建立连接才能收发消息,udp套接字则不需要;tcp套接字使用send,recv收发消息,udp套接字使用sendto,recvfrom;socket套接字的属性: 【1】 sockfd.type 套接字类型; 【2】 sockfd.family 套接字地址类型; 【3】 sockfd.getsockname() 获取套接字绑定地址; 【4】 sockfd.fileno() 获取套接字的文件描述符; 【5】 sockfd.getpeername() 获取连接套接字客户端地址; 【6】 sockfd.setsockopt(level,option,value) 设置套接字选项; level:选项类别;SOL_SOCKET option: 具体选项内容; value: 选项值。
Struct模块进行数据打包: 服务端:
from socket import * import struct # 与客户端格式一直 st = struct.Struct("i16sif") #udp套接字 s = socket(AF_INET,SOCK_DGRAM) s.bind(('127.0.0.1',8888)) # 打开一个保存信息的文件 f = open('student.txt','a') while True: data,addr = s.recvfrom(1024) # (1,b'Lily',14,94.5) data = st.unpack(data) # 写入文件 info = "%d %-10s %d %.1f\n"%data f.write(info) f.flush() f.close() s.close()客户端:
import struct from socket import * # 设置数据结构 st = struct.Struct("i16sif") # 创建udp套接字 s = socket(AF_INET,SOCK_DGRAM) ADDR = ('127.0.0.1',8888) while True: print("===========================") id = int(input("学号:")) name = input("姓名:").encode() age = int(input("年龄:")) score = float(input("得分:")) # 将数据打包 data = st.pack(id,name,age,score) s.sendto(data,ADDR) # 发送给服务端 s.close()可以使用struct模块直接调用pack unpack。此时这两函数第一个参数传入fmt。其他用法功能相同。
下一篇讲述:并发编程
