IO网络编程:都是干货哦!

IO操作

涉及到在内存中存在数据叫喊的操作。

程序分类

** 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语句块内使用。

刷新缓冲区
刷新缓冲区条件:

  1. 缓冲区被写满

  2. 程序执行结束或者文件对象被关闭

  3. 行缓冲遇到换行

  4. 程序中调用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对象获取对应的文件描述符。
文件管理函数

  1. 获取文件大小
    os.path.getsize(file)
  2. 查看文件列表
    os.listdir(dir)
  3. 查看文件是否存在
    os.path.exists(file)
  4. 判断文件类型
    os.path.isfile(file)
  5. 删除文件
    os.remove(file)

网络编程基础

计算机网络功能主要实现资源共享,数据信息的传递。

OSI七层模型:(是网络通络通信工作流程标准化)

应用层:
提供用户服务,具体功能应用程序。
表示层:
数据的压缩优化加密。
会话层:
建立用户级的连接,选择适当的传输服务。
传输层:
提供传输服务。
网络层:
路由选择,网络互联。
数据链路层:
进行数据的交互,控制具体数据发送。
物理层:
提供数据传输的硬件保证,网卡接口,传输介质。

四层模型:(TCP、IP模型)

应用层:
( 应用层[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协议的数据传输)

  1. 传输特点 : 传输过程没有连接和断开,数据收发自由随意。
  2. 适用情况 : 网络较差,对传输可靠性要求不高。比如:网络视频,群聊,广播

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:

由上面的代码,你也已经对套接字**(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套接字编程区别:

  1. 流式套接字是以字节流方式传输数据,数据报套接字以数据报形式传输;
  2. tcp套接字会有粘包,udp套接字有消息边界不会粘包;
  3. tcp套接字保证消息的完整性,udp套接字则不能;
  4. tcp套接字依赖listen accept建立连接才能收发消息,udp套接字则不需要;
  5. 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。其他用法功能相同。

HTTP传输:

  1. 用途 : 网页获取,数据的传输;
  2. 特点:
    应用层协议,传输层使用tcp传输;
    简单,灵活,很多语言都有HTTP专门接口;
    无状态,协议不记录传输内容;
    http1.1 支持持久连接,丰富了请求类型;
  3. 网页请求过程:
    1.客户端(浏览器)通过tcp传输,发送http请求给服务端;
    2.服务端接收到http请求后进行解析;
    3.服务端处理请求内容,组织响应内容;
    4.服务端将响应内容以http响应格式发送给浏览器;
    5.浏览器接收到响应内容,解析展示;
    http请求:
    请求行:具体ed请求类别和请求内容;
    请求类别: 每个请求类别表示要做不同的事情;
    请求头:对请求的进一步解释和描述。
    http响应:
    响应格式: 响应行,响应头,空行,响应体。
    响应行:反馈基本的响应情况;
    响应码:
    1xx 提示信息,表示请求被接收;
    2xx 响应成功;
    3xx 响应需要进一步操作,重定向;
    4xx 客户端错误;
    5xx 服务器错误;
    响应头:对响应内容的描述;
    响应体:响应的主体内容信息;
    代码实现:
"""
http请求响应演示
"""

from socket import *

# tcp服务端
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 端口立即重用
s.bind(('127.0.0.1',8000))
s.listen(5)

c,addr = s.accept()
print("Connect from",addr)
data = c.recv(4096).decode()
print(data)  # http请求

html = """HTTP/1.1 200 OK
Content-Type: text/html

<h1>Hello World</h1>
"""
c.send(html.encode())

c.close()
s.close()
"""
编写一个http服务端程序
     如果浏览器的请求内容 /
     响应码为  200  OK,将index.html内容作为响应内容

     如果浏览器的请求是其他的
     响应码为  404  Not Found  内容为 "Sorry.."
"""
from socket import *

# 与客户端交互
def handle(connfd):
    # 获取http请求
    data = connfd.recv(4096).decode()
    request_line = data.split('\n')[0] # 请求行
    info = request_line.split(' ')[1] # 请求内容
    # 看一下请求内容是不是/
    if info == '/':
        with open('index.html') as f:
            # 组织http响应
            response = "HTTP/1.1 200 OK\r\n"
            response += "Content-Type:text/html\r\n"
            response += '\r\n'
            response += f.read()
    else:
        response = "HTTP/1.1 404 Not Found\r\n"
        response += "Content-Type:text/html\r\n"
        response += '\r\n'
        response += "<h1>Sorry...</h1>"
    # 发送给浏览器
    connfd.send(response.encode())

# 搭建网络
def main():
    sockfd = socket()
    sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    sockfd.bind(('0.0.0.0',8000))
    sockfd.listen(3)
    while True:
        connfd,addr = sockfd.accept()
        print("Connect from",addr)
        # 处理客户端请求
        handle(connfd)

main()

下一篇讲述:并发编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值