网络编程(二)
2022/4/15 22:14:12
本文主要是介绍网络编程(二),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
网络编程(二)
socket套接字简介
# socket套接字是一门技术 socket套接字可以帮我们实现C/S架构的程序两端交互 socket套接字可以通过python内置的socket模块快速实现OSI七层操作 """ 以后我们写软件连socket的影子都看不到 因为被封装起来 socket是最底层的原理 很多框架都封装了 其实我们不需要深入研究 """
socket模块
# 编程思想 对于C/S架构的程序,无论编写还是运行,都要遵循: '优先考虑服务端,有了服务才能有客户' # 服务端代码 import socket server = socket.socket() # 获取连接对象 server.bind(('127.0.0.1',8080)) # 给连接对象绑定地址 server.listen(5) # 允许最大排队数 这个数加上正在连接数就是最大连接数 sock, addr = server.accept() # 阻塞程序,没有获取到连接的客户端会阻塞程序运行 print(addr) while True: # 循环通信 data = sock.recv(1024) # 从连接里获取客户端的数据 print(data.decode('utf8')) msg = input('>').strip() sock.send(msg.encode('utf8')) # 通过连接把数据发给客户端 sock.close() # 关闭与客户端连接 server.close() # 关闭连接对象 # 客户端代码 import socket client = socket.socket() # 获取连接对象 client.connect(('127.0.0.1',8080)) # 绑定连接服务端的地址 while True: # 循环通信 msg = input('>').strip() client.send(msg.encode('utf8')) # 发数据到服务端 data = client.recv(1024) # 获取服务端发来的数据 print(data.decode('utf8')) client.close() # 关闭连接 ########################### 服务端与客户端首次交互 一边是recv那么另一边必须是send 两边不能相同 否则就'冷战'了 ###########################
通信循环
# 思路 1.所有通信消息要用户事实输入 利用input获取用户输入信息 2.接收一次消息之后不能结束程序,应当获取输入,返回消息,然后等待下一次接发消息 利用While循环实现 # 代码编写 详见上段代码
代码优化及链接循环
1.不能发空消息 搞个if判断len(用户输入即可) 2.反复重启服务端可能会报错>>>:address in use 这个错在苹果电脑报的频繁 windows频率较少 from socket import SOL_SOCKET,SO_REUSEADDR server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 在bind前加 3.链接循环 """ 如果是windows 客户端异常退出之后服务端会直接报错 处理方式 异常处理 如果是mac或linux 服务端会接收到一个空消息 处理方式 len判断 """ 客户端如果异常断开 服务端代码应该重新回到accept等待新的客人 # 目前我们的服务端只能实现一次服务一个人 不能做到同事服务多个 学了并发才可以实现
半连接池
listen(5) # py文件默认同一时间只能运行一次 如果想单独分开运行多次 # 半连接池 设置的最大等待人数 >>>: 节省资源 提高效率
黏包问题
# 客户端 data1 ='aaa' data2 ='aaa' data3 ='aaa' client.send(data1.encode('utf8')) client.send(data2.encode('utf8')) client.send(data3.encode('utf8')) # 服务端 data1 = sock.recv(1024) print(data1) data2 = sock.recv(1024) print(data2) data3 = sock.recv(1024) print(data3) # 客户端输出 b'aaaaaaaaa' b'' b'' 为什么发了三次数据,结果全都在第一次数据里? """ # TCP协议的特点 会将数据量比较小并且时间间隔比较短的数据整合到一起发送 并且还会受制于recv括号内的数字大小(核心问题!!!) 流式协议:跟水流一样不间断 """ """ 问题产生的原因其实是因为recv括号内我们不知道即将要接收的数据到底多大 如果每次接收的数据我们都能够精确的知道它的大小 那么肯定不会出现黏包 """ eg: data1 = sock.recv(3) print(data1) data2 = sock.recv(3) print(data2) data3 = sock.recv(3) print(data3) # 客户端输出 b'aaa' b'aaa' b'aaa'
解决黏包问题
解决思路: 我们可以发送固定大小的数据,客户端接收就不会出现黏包 # struct模块 import struct data1 = 'Hello world!' data2 = 'afdkjhfdafklajflkhaslfjahfjkahflksafjl' print(len(data1), len(data2)) # 12 38 ret1 = struct.pack('i', len(data1)) ret2 = struct.pack('i', len(data2)) print(len(ret1), len(ret2)) # 4 4 res1 = struct.unpack('i',ret1) res2 = struct.unpack('i',ret2) print(res1, res2) # (12,) (38,) # 具体解决黏包思路 1.先将用struct模块打包成固定长度 2.把打包后的长度发过去 3.对方用unpack解析获取真实长度 4.根据真实长度用recv(真实长度)接收数据
代码演示
1.编写一个cs架构的软件 就两个功能 一个视频下载:从服务端下载视频 一个视频上传:从客户端上传视频 """ 只要实现就可以 无需整合(如果能做到更好) """ # 代码 服务端 import socket # 获取连接对象 import struct server_packer = socket.socket() server_packer.bind(('127.0.0.1',8081)) server_packer.listen(1) sock,addr = server_packer.accept() # 读取视频文件 with open('1.mp4','rb') as f: data = f.read() # 打包 ret = struct.pack('i', len(data)) # 发送打包后的数据 sock.send(ret) # 发送真实数据 sock.send(data) sock.close() server_packer.close() 客户端 import struct import socket # 获取连接对象 client = socket.socket() client.connect(('127.0.0.1',8081)) # 获取打包后长度并解析 ret = client.recv(4) res = struct.unpack('i',ret) # 根据解析的长度获取真实数据 data = client.recv(res[0]) # 写入文件 with open('2.mp4','wb') as f: f.write(data) client.close()
这篇关于网络编程(二)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15鸿蒙生态设备数量超8亿台
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?