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. vue3 快速入门系列 —— 状态管理 pinia

    其他章节请看: vue3 快速入门 系列 pinia vue3 状态管理这里选择 pinia. 虽然 vuex4 已支持 Vue 3 的 Composition API,但是 vue3 官网推荐新的应 ...

  2. XAMPP安装与部署使用

    #注:本文章资料借鉴自于Sunny王维,地址:https://blog.csdn.net/qq_36595013/article/details/80373597 [一]XAMPP介绍 XAMPP. ...

  3. Linux内核之SPI协议

    SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行的行业标准,但是并没有像I2C那样有标准文档,它还有主从.可片选的特性. 图源自Serial Periphe ...

  4. 在Deepin 20.2系统中换源并全新图解安装MySQL数据库

    在Deepin 20.2系统中换源并全新图解安装MySQL数据库 https://www.ywnz.com/linuxysjk/9249.html ubuntu下apt-get彻底卸载mysql 删除 ...

  5. ruby中的Hash排序

    参考: https://blog.csdn.net/xing102172/article/details/9163607 For example: h={'a'=>2, 'c'=>1, ' ...

  6. Nginx教程+笔记

    Nginx 学习视频: 2020最新 Nginx教程全面讲解(Nginx快速上手) https://www.bilibili.com/video/BV1W54y1z7GM?t=553&p=14 ...

  7. WEB服务与NGINX(14)-NGINX的压缩功能

    1. nginx压缩功能 nginx支持对指定类型的文件进行压缩后再回传给客户端,而且压缩可以设置压缩比,压缩后的文件会明显变小,有助于降低出口带宽的利用率,但是会占用一定的CPU资源. nginx实 ...

  8. 智能勘探 | AIRIOT智慧油田管理解决方案

      石油勘探和开采地处偏远地区,涉及面广且生产规模大.特殊的作业环境下,使得工作人员作业条件艰苦,仅靠人工值守难度很大,不可避免的遇到一系列硬核挑战: 1.设备维护难度较高: 2.采油厂分布地域广.分 ...

  9. Spring6 对 集成MyBatis 开发运用(附有详细的操作步骤)

    1. Spring6 对 集成MyBatis 开发运用(附有详细的操作步骤) @ 目录 1. Spring6 对 集成MyBatis 开发运用(附有详细的操作步骤) 每博一文案 2. 大概的实现步骤概 ...

  10. tkinter小例子

    from tkinter import * def on_click(): label['text'] = text.get() root = Tk(className='hello') root.m ...