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网络编程的更多相关文章

  1. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  2. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  3. python网络编程——IO多路复用之select

    1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...

  4. python网络编程05 /TCP阻塞机制

    python网络编程05 /TCP阻塞机制 目录 python网络编程05 /TCP阻塞机制 1.什么是拥塞控制 2.拥塞控制要考虑的因素 3.拥塞控制的方法: 1.慢开始和拥塞避免 2.快重传和快恢 ...

  5. Python网络编程基础|百度网盘免费下载|零基础入门学习资料

    百度网盘免费下载:Python网络编程基础|零基础学习资料 提取码:k7a1 目录: 第1部分 底层网络 第1章 客户/服务器网络介绍 第2章 网络客户端 第3章 网络服务器 第4章 域名系统 第5章 ...

  6. Python网络编程基础 PDF 完整超清版|网盘链接内附提取码下载|

    点此获取下载地址提取码:y9u5 Python网络编程最好新手入门书籍!175个详细案例,事实胜于雄辩,Sockets.DNS.Web Service.FTP.Email.SMTP.POP.IMAP. ...

  7. Python网络编程之网络基础

    Python网络编程之网络基础 目录 Python网络编程之网络基础 1. 计算机网络发展 1.1. OSI七层模型 1.2. 七层模型传输数据过程 2. TCP/IP协议栈 2.1 TCP/IP和O ...

  8. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  9. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  10. python网络编程-01

    python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...

随机推荐

  1. k8s网页访问实战

    流程: 客户端访问--->ingress七层代理---->service四层代理---->deployment 详细情况:https://www.cnblogs.com/yangme ...

  2. Oracle细粒度审计策略

    场景:经常需要查看某些表做了哪些操作. Oracle中,可以添加细粒度策略来获取,如下: begin dbms_fga.add_policy(object_schema => 'portxx', ...

  3. 关于ITIL的习惯性误解

    关于ITIL的习惯性误解 1. ITIL是标准?不是!ITIL本质是一套适合西方社会信息化阶段的 模板原版教材 最佳实践(Best Practice),不是标准. 大量的培训师和咨询顾问将其包装成&q ...

  4. 【工程实践】go语言实现MerkleTree

    简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其哈希值: 非叶子节点(包括中间节点和根节点)的内容为它的两个孩子节点内容的哈希值. 所以底层 ...

  5. Mac远程控制工具有哪些

    适用于Mac的远程控制工具有很多,这里我们给大家列举五个常用软件. 1.Apple Remote Desktop 苹果自带远程桌面正如其名称所承诺的那样.作为 Apple 出品的应用程序,您可以想象它 ...

  6. Python:Python对象模型与序列迭代陷阱

    1. Python对象模型与浅拷贝/深拷贝 1.1 Python对象模型和引用 在我们讲解Python的序列修改陷阱之前,先巩固一下Python的对象模型和浅拷贝/深拷贝的知识. 众所周知,Pytho ...

  7. kubernets之了解Qos等级

    一  Qos的种类 BestEffort(优先级最低) Burstable(中等优先级) Guaranteed(最高优先级) 二  Qos的作用 众所周知,节点上面的limits允许超卖,当节点上面的 ...

  8. Linux中默认的shell如何切换为其他类型的shell

    1.一般linux系统会默认使用一种shell,比如我当前系统使用的默认shell是bash,可以使用如下方法查看. [root@node5 ~]# echo $SHELL /bin/bash 2.当 ...

  9. 一文教你基于LangChain和ChatGLM3搭建本地知识库问答

    本文分享自华为云社区<[云驻共创]LangChain+ChatGLM3实现本地知识库,转华为云ModelArts,实现大模型AI应用开发> ,作者:叶一一. 一.前言 本期华为云的讲师是华 ...

  10. 【C#】关于ACCESS数据库insert into报错:标准表达式中数据类型不匹配

    如果插入列有日期/时间类型,使用C#时,var ptime = new OleDbParameter("@DtTime", OleDbType.Date); OleDbType.D ...