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. VisualStudio 调试时会不断刷新 WPF 应用渲染

    在 VisualStudio 附加调试和没有用 VisualStudio 附加调试时,对应用程序是有不同的影响,如 VisualStudio 设计器将会在附加调试 WPF 应用的时候,不断刷新 WPF ...

  2. 003_Orcad菜单讲解与偏好设置

    003_Orcad菜单讲解与偏好设置 菜单栏用的比较多的是File和Options项. 网格建议用lines,比较方便对齐. Auto Reference和Intertool Commuication ...

  3. C语言程序设计-笔记8-结构

    C语言程序设计-笔记8-结构 例9-1  输出平均分最高的学生信息.根据学生的基本信息包括学号.姓名.三门课程成绩以及个人平均成绩.输入n个学生的成绩信息,计算并输出平均分最高的学生信息. #incl ...

  4. 【web安全】修改和配置tomcat版本信息

    场景 目前网络安全的越来越受重视,tomcat作为重要的web容器被广泛应用,如何隐藏信息保证.在开放网络世界中,不易被攻击. 操作思路 1.进入Tomcat文件中的lib文件夹,将catalina. ...

  5. ansible系列(29)--ansible的Jinja2语法及应用

    目录 1. Ansible Jinja2 1.1 jinja2语法结构 1.2 jinja2中{{ }}中的运算符 1.3 jinja2中for循环和if判断示例 1.4 Jinja2管理Nginx负 ...

  6. mongodb的备份与恢复详解

    简单 Mongodb导出与导入 1: 导入/导出可以操作的是本地的mongodb服务器,也可以是远程的.所以,都有如下通用选项:-h host 主机--port port 端口-u username ...

  7. uniapp android app 铃声静音,真正的免打扰

    需要加入这个权限: <uses-permission android:name=\"android.permission.ACCESS_NOTIFICATION_POLICY\&quo ...

  8. CSS——组合选择器

    1.后代选择器(包括儿子和孙子) .c1 .c2{ color: red; } 2.子代选择器(只选择儿子) .c3 > .c5{ color: red; } 3.与选择器 选择p标签下面的.c ...

  9. HTML——超链接标签

    一.超链接标签的基本使用 超链接是浏览者和服务器的交互的主要手段,也叫超级链接或a链接,是网页中指向一个目标的连接关系,这个目标可以是网页.网页中的具体位置.图片.邮件地址.文件.应用程序等. 超链接 ...

  10. RCTF 2024 WEB wp

    RCTF 2024 WEB wp 前言 赛后复现,proxy发现自己真是个呆b... what_is_love 首先拿key1,sql语句处有注入,可以盲注拿key1的值 import request ...