11-Python网络编程
socket包介绍
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
创建一个TCP协议的socket:
socket.socket()
创建一个UDP协议的socket:
socket.socket(type = socket.SOCK_DGRAM)
socket包的特点:
- 使用bytes类型发送和接收数据。
- 接收数据时:linux下若连接关闭,则接收空;Windows下连接关闭,则报错。
发送数据:
send() #可能一次不会发送完(超过MTU)
sendall() #循环调用send()将数据发送完(一般使用sendall即可)
sendto(msg1,client_addr) #发送数据时指定对端地址
接收数据:
recv(1500) #接收数据(最多1500字节)
recvfrom(1024) #不仅能接收数据,还能获取对方ip(适用于未知ip的情况)
使用TCP传输数据
服务端:
import socket
sk = socket.socket() #创建套接字对象
address = ('127.0.0.1', 8000)
sk.bind(address) #绑定监听IP和端口
sk.listen(3) # 最大连接数(超过则拒绝)
conn, addr = sk.accept() #接收连接(返回一个元组)
conn.sendall(bytes("你好", "utf8")) #发送数据(转为bytes发送)
s = conn.recv(1024) #接收数据,最大接收1024B数据
print(str(s, "utf8")) # 转为UTF-8输出
conn.close()
sk.close()
客户端:
import socket
sk = socket.socket() #创建套接字对象
address = ('127.0.0.1', 8000)
sk.connect(address) #连接到服务端
sk.sendall(bytes("你好", "utf8")) #发送数据(转为bytes发送)
s = sk.recv(1024) #接收数据,最大接收1024B数据
print(str(s, "utf8")) #转为UTF-8输出
sk.close()
解释:
- 发送和接收的顺序无要求
- sk.accept()和conn.close()包含三次握手和四次挥手,UDP协议是没有的。
使用UDP传输数据
服务端:
import socket
sk = socket.socket(type = socket.SOCK_DGRAM) #UDP协议必须加上 type=socket.SOCK_DGRAM
sk.bind(('127.0.0.1',9000))
msg,client_addr = sk.recvfrom(1024) #recvfrom用于不知道对方ip时,获取到ip给client_addr
msg = msg.decode('utf-8')
print(msg)
msg1 = input('>>>').encode('utf-8') #输入数据
sk.sendto(msg1,client_addr)
sk.close()
客户端:
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
inp = input('>>>').encode('utf-8') #输入数据
sk.sendto(inp, ('127.0.0.1', 9000))
msg = sk.recv(1024).decode('utf-8') #这里不需要使用recvfrom,因为知道对方ip地址
print(msg)
sk.close()
粘包
粘包:原本应该分离的多个数据包,变成了一个包
发送方粘包:缓冲区中存在多个数据包,合成一起发送
接收方粘包:来不及处理缓冲区中的包,多个数据包一起处理
因为算法原因,TCP会产生粘包现象,而UDP永远不会。
粘包现象
服务端:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8888))
sk.listen()
conn, addr = sk.accept()
while 1:
conn.send(b'hello')
conn.send(b'world')
conn.close()
sk.close()
客户端:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8888))
while 1:
msg1 = sk.recv(1024) #接收服务器返回来的数据
print('msg1:', msg1)
msg2 = sk.recv(1024)
print('msg2:', msg2)
sk.close()
结果:
msg1: b'hello'
msg2: b'world'
msg1: b'helloworld' #产生粘包现象
msg2: b'hello'
msg1: b'world'
msg2: b'hello'
msg1: b'world'
msg2: b'hello'
msg1: b'worldhello' #产生粘包现象
msg2: b'world'
msg1: b'hello'
msg2: b'world'
结果:
连续发送和接收数据,就有可能产生粘包。
解决粘包问题-struct模块
解决思路:
- 发送方:先发送一个头部,告诉接收端应该接收多少数据,再发送真实数据。
- 接收方:先接收一个头部,再根据头部信息,接收相应字节的数据。
struct模块中的方法简介:
pack(fmt, v1, v2, ...) #按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)
unpack(fmt, string) #按照给定的格式(fmt)解析字节流string,返回解析出来的tuple
calcsize(fmt) #计算给定的格式(fmt)占用多少字节的内存
示例:
size = struct.pack('i', 50) #将整数50转化为4个字节的struct类型
格式(上例中的fmt)
| Format | C Type | Python | 字节数 |
|---|---|---|---|
| x | pad byte | no value | 1 |
| c | char | string of length 1 | 1 |
| b | signed char | integer | 1 |
| B | unsigned char | integer | 1 |
| ? | _Bool | bool | 1 |
| h | short | integer | 2 |
| H | unsigned short | integer | 2 |
| i | int | integer | 4 |
| I | unsigned int | integer or long | 4 |
| l | long | integer | 4 |
| L | unsigned long | long | 4 |
| q | long long | long | 8 |
| Q | unsigned long long | long | 8 |
| f | float | float | 4 |
| d | double | float | 8 |
| s | char[] | string | 1 |
利用struct模块解决粘包问题
服务端:
import socket,struct
sk = socket.socket()
sk.bind(('127.0.0.1', 8888))
sk.listen()
conn, addr = sk.accept()
while 1:
s = b'hello'
size = struct.pack('i', len(s))
conn.send(size) # 先发送头部
conn.send(s) # 再发送真实数据
s = b'world'
size = struct.pack('i', len(s))
conn.send(size) # 先发送头部
conn.send(s) # 再发送真实数据
conn.close()
sk.close()
客户端:
import socket,struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8888))
while 1:
size = sk.recv(4) #先接收头部
size = struct.unpack('i', size)[0] #转化为整数
msg1 = sk.recv(size).decode("UTF-8")#接收真实数据
print('msg1:', msg1)
size = sk.recv(4) #先接收头部
size = struct.unpack('i', size)[0] #转化为整数
msg2 = sk.recv(size).decode("UTF-8")#接收真实数据
print('msg2:', msg2)
sk.close()
聊天小程序
服务端:
# server.py 服务端
import socket
ip_port=('127.0.0.1',8081)
udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #DGRAM:datagram 数据报文的意思,象征着UDP协议的通信方式
udp_server_sock.bind(ip_port) #你对外提供服务的端口就是这一个,所有的客户端都是通过这个端口和你进行通信的
while True:
qq_msg,addr=udp_server_sock.recvfrom(1024)# 阻塞状态,等待接收消息
print('来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))
back_msg=input('回复消息: ').strip()
udp_server_sock.sendto(back_msg.encode('utf-8'),addr)
udp_server_sock.recv(0)
客户端:
import socket
BUFSIZE=1024
udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
qq_name_dic={
'taibai':('127.0.0.1',8081),
'Jedan':('127.0.0.1',8081),
'Jack':('127.0.0.1',8081),
'John':('127.0.0.1',8081),
}
while True:
while 1:
qq_name=input('请选择聊天对象: ').strip()
if qq_name not in qq_name_dic:
print('没有这个聊天对象')
continue
break
while True:
msg=input('请输入消息,回车发送,输入q结束和他的聊天: ').strip()
if msg == 'q':
break
msg = '发给' + qq_name + ': ' + msg
if not msg:continue
udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])# 必须带着自己的地址,这就是UDP不一样的地方,不需要建立连接,但是要带着自己的地址给服务端,否则服务端无法判断是谁给我发的消息,并且不知道该把消息回复到什么地方,因为我们之间没有建立连接通道
udp_client_socket.recv(0)
back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)# 同样也是阻塞状态,等待接收消息
print('来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))
udp_client_socket.close()
11-Python网络编程的更多相关文章
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
- Python 网络编程(一)
Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...
- python网络编程——IO多路复用之select
1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...
- python网络编程05 /TCP阻塞机制
python网络编程05 /TCP阻塞机制 目录 python网络编程05 /TCP阻塞机制 1.什么是拥塞控制 2.拥塞控制要考虑的因素 3.拥塞控制的方法: 1.慢开始和拥塞避免 2.快重传和快恢 ...
- Python网络编程基础|百度网盘免费下载|零基础入门学习资料
百度网盘免费下载:Python网络编程基础|零基础学习资料 提取码:k7a1 目录: 第1部分 底层网络 第1章 客户/服务器网络介绍 第2章 网络客户端 第3章 网络服务器 第4章 域名系统 第5章 ...
- Python网络编程基础 PDF 完整超清版|网盘链接内附提取码下载|
点此获取下载地址提取码:y9u5 Python网络编程最好新手入门书籍!175个详细案例,事实胜于雄辩,Sockets.DNS.Web Service.FTP.Email.SMTP.POP.IMAP. ...
- Python网络编程之网络基础
Python网络编程之网络基础 目录 Python网络编程之网络基础 1. 计算机网络发展 1.1. OSI七层模型 1.2. 七层模型传输数据过程 2. TCP/IP协议栈 2.1 TCP/IP和O ...
- Python学习(22)python网络编程
Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...
- Day07 - Python 网络编程 Socket
1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...
- python网络编程-01
python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...
随机推荐
- k8s网页访问实战
流程: 客户端访问--->ingress七层代理---->service四层代理---->deployment 详细情况:https://www.cnblogs.com/yangme ...
- Oracle细粒度审计策略
场景:经常需要查看某些表做了哪些操作. Oracle中,可以添加细粒度策略来获取,如下: begin dbms_fga.add_policy(object_schema => 'portxx', ...
- 关于ITIL的习惯性误解
关于ITIL的习惯性误解 1. ITIL是标准?不是!ITIL本质是一套适合西方社会信息化阶段的 模板原版教材 最佳实践(Best Practice),不是标准. 大量的培训师和咨询顾问将其包装成&q ...
- 【工程实践】go语言实现MerkleTree
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其哈希值: 非叶子节点(包括中间节点和根节点)的内容为它的两个孩子节点内容的哈希值. 所以底层 ...
- Mac远程控制工具有哪些
适用于Mac的远程控制工具有很多,这里我们给大家列举五个常用软件. 1.Apple Remote Desktop 苹果自带远程桌面正如其名称所承诺的那样.作为 Apple 出品的应用程序,您可以想象它 ...
- Python:Python对象模型与序列迭代陷阱
1. Python对象模型与浅拷贝/深拷贝 1.1 Python对象模型和引用 在我们讲解Python的序列修改陷阱之前,先巩固一下Python的对象模型和浅拷贝/深拷贝的知识. 众所周知,Pytho ...
- kubernets之了解Qos等级
一 Qos的种类 BestEffort(优先级最低) Burstable(中等优先级) Guaranteed(最高优先级) 二 Qos的作用 众所周知,节点上面的limits允许超卖,当节点上面的 ...
- Linux中默认的shell如何切换为其他类型的shell
1.一般linux系统会默认使用一种shell,比如我当前系统使用的默认shell是bash,可以使用如下方法查看. [root@node5 ~]# echo $SHELL /bin/bash 2.当 ...
- 一文教你基于LangChain和ChatGLM3搭建本地知识库问答
本文分享自华为云社区<[云驻共创]LangChain+ChatGLM3实现本地知识库,转华为云ModelArts,实现大模型AI应用开发> ,作者:叶一一. 一.前言 本期华为云的讲师是华 ...
- 【C#】关于ACCESS数据库insert into报错:标准表达式中数据类型不匹配
如果插入列有日期/时间类型,使用C#时,var ptime = new OleDbParameter("@DtTime", OleDbType.Date); OleDbType.D ...