网络通信与并发编程(二)基于tcp的套接字、基于udp的套接字、粘包现象
基于tcp的套接字
文章目录
- 基于tcp的套接字
- 一、套接字的工作流程
- 二、基于tcp的套接字通信
- 三、基于udp的套接字通信
- 四、粘包现象
一、套接字的工作流程
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
二、基于tcp的套接字通信
基于上面的套接字工作原理,我们可以用python编写处如下的一段代码:
#服务端
import socket#socket.AF_INET表示套接字,socket.SOCK_STREAM表示tcp,tcp也称为流式协议
#创建套接字对象
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #绑定服务端ip和端口
phone.bind(('127.0.0.1',8081))#开始监听,listen表示半连接池,限制的是请求数
phone.listen(5)# 连接循环,服务端需要一直开启等待客户端的连接(连接循环)
while True: #收到客户端的请求,通过三次握手与四次挥手建立通信通道#conn是建立的通信通道,client_addr是客户端的信息#当没有建立链接请求时,服务端会一直停在phone.accept()处conn,client_addr=phone.accept()#通信通道建立完成,与客户端持续通信(通信循环)while True: try:print('服务端正在收数据...')#为了降低内存的压力,需要限制每次接收的字节数#当没有接收到客户端的消息时,服务端会一直停在conn.recv(1024)处data=conn.recv(1024) #linux中客户端中断后服务端会接收空字符,此时需要跳出通信循环if len(data) == 0:break print('来自客户端的数据',data)#回复客户端的信息conn.send(data.upper())#windows中客户端连接中断会报错,需要用try推出通信循环except ConnectionResetError:break#关闭通信通道,服务端准备与下一个客户端建立通信链接conn.close()#关闭套接字对象
phone.close()
#客户端
import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#客户端不需要绑定ip和端口,只需向服务端的ip和端口发送请求
phone.connect(('127.0.0.1',8080)) # 指定服务端ip和端口#通信循环
while True: msg=input('>>: ').strip()#套接字中无法发送空字符if len(msg) == 0:continuephone.send(msg.encode('utf-8'))data=phone.recv(1024)print(data)phone.close()
如果在重启服务端的过程中出现如下的情况表示服务端仍在四次挥手的time_wait状态(服务端进程依然在后台运行),此时可以采取两种方法。
- 修改绑定给服务端的端口号
- 在绑定服务端的ip和端口前加上phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
三、基于udp的套接字通信
基于udp协议编写的套接字如下:
#服务端
import socket#socket.SOCK_DGRAM表示udp协议,udp是数据报协议
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))#udp协议不需要建立通信通道,因此它是不可靠的通信协议
#简单来说tcp是一对一的收发消息,一个客户端结束才会回应其他客户端
#udp是一对多的收发消息,由客户端发送消息时服务端就会回应
while True:#接收客户端的消息data,client_addr=server.recvfrom(1024)print('===>',data,client_addr)#发送消息给客户端,由于没有链接通道,发送信息需要带上客户端的ip和端口信息server.sendto(data.upper(),client_addr)server.close()
#客户端
import socketclient=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True:msg=input('>>: ').strip()#向服务端的ip和端口发送信息client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))data,server_addr=client.recvfrom(1024)print(data)client.close()
四、粘包现象
将服务端的代码作如下的修改:
import socket,subprocessphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))phone.listen(5)while True:conn,client_addr=phone.accept()while True:try:data=conn.recv(1024)if len(data) == 0: breaka=subprocess.Popen(data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)res=a.stdout.read()conn.send(res)except ConnectionResetError:breakconn.close()
phone.close()
我们尝试在客户端通过指令tasklist查看服务端的进程列表,第一次客户端向服务端发送tasklist命令返回如下的结果:
映像名称 PID 会话名 会话# 内存使用
========================= ======== ================ =========== ============
System Idle Process 0 Services 0 8 K
System 4 Services 0 12 K
Registry 296 Services 0 26,600 K
smss.exe 892 Services 0 528 K
csrss.exe 1124 Services 0 2,840 K
wininit.exe 1236 Services 0 3,400 K
services.exe 1308 Services 0 8,912 K
lsass.exe 1332 Services 0 20,172 K
svchost.exe 1460 Services 0 29,432 K
fontdrvhost.exe 1484 Services 0 104 K
WUDFHost.exe 1536 Services 0 2,952 K
svchost.
第二次当客户端向服务端发送ping www.baidu.com时会发现返回的结果依然是客户端的进程列表:
exe 1596 Services 0 15,092 K
svchost.exe 1640 Services 0 6,416 K
WUDFHost.exe 1764 Services 0 21,224 K
svchost.exe 1876 Services 0 3,868 K
svchost.exe 1884 Services 0 7,436 K
svchost.exe 1904 Services 0 4,420 K
svchost.exe 1940 Services 0 9,876 K
svchost.exe 1948 Services 0 7,880 K
svchost.exe 2036 Services 0 7,128 K
svchost.exe 1304 Services 0 15,372 K
svchost.exe 2128 Services 0 4,932 K
svchost.exe 2140 Services 0 6,348 K
svchost.exe 2148 Services 0 7,032 K
svchost.exe
这是怎么回事呢?我们知道tcp协议是流式协议,也就是说基于tcp协议发送消息时,服务端套接字会把需要发送的消息给自己的操作系统,而自己的操作系统将这些消息一段一段发送给客户端的操作系统,由于是一段一段的发送,客户端无法判断一条消息的始末,所以客户端套接字每次只从操作系统中取字节数限制字节的消息,当发送的消息量过大时,只有一部分消息会被接收并打印到终端上,剩余的消息依然在客户端的操作系统中。当我们再次向服务端发送消息接收消息以后,套接字会先接收上次没有接受完的消息,再接受新的消息,这就产生了粘包现象。
另外如果tcp多次短间隔的发送消息,发送端的套接字会将这些消息并再一起发送,这样会发送接受方的另一种粘包问题。
这时候肯定有人要说如果我们不限制套接字每次接受的字节数是不是就能解决这个问题呢?问题是如果我们接受的是一个很大的内容,比如50g,套接字会将接受的消息全部读入内存,这就会引发内存爆满的情况,显然这种解决方式是不可取的。
udp协议是数据报式的协议,也就是说udp每次收发消息都是以一个数据报为单位的(套接字会给每次的消息加上消息头),每次接受消息都会一次取完。如果服务端接收的字节限制比接收内容小时,多出来的内容会丢失(windows中会报错),而不会发送粘包的问题。由于udp的消息都含有消息头,所以即便是短时间内发送多次消息,也不会发生上面说到的第二种粘包问题。
tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头。
相关文章:

网络通信与并发编程(二)基于tcp的套接字、基于udp的套接字、粘包现象
基于tcp的套接字 文章目录 基于tcp的套接字一、套接字的工作流程二、基于tcp的套接字通信三、基于udp的套接字通信四、粘包现象 一、套接字的工作流程 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个…...

400行程序写一个实时操作系统(十):用面向对象思想构建抢占式内核
前言 通过前几章的学习,我们学会了如何为RTOS设计一个合理的内存管理算法。现在,是时候学习设计RTOS内核了。 关于RTOS内核的文章也有很多,但都有一点先射箭再化靶子的意味。要么是代码连篇解释却寥寥无几,要么是要先怎么样再怎么…...

C#学习笔记(九)
C#学习笔记(九) 第六章 面向对象编程(一)类与对象、字段与属性一、类与对象正确的理解1. 什么是类?2.什么是对象?3. 类与对象的区别 二、类的基本规范和对象使用1. 类的规范 三、类的访问修饰符(…...

意外发现!AI写作这样用,热点文章轻松超越同行90%!
做自媒体,写热点文章很重要。 热点自带流量,能很快吸引不少读者。 可很多自媒体新手很犯愁。 干货文还能勉强写出来,碰到热点文就不知咋办了。 为啥写热点文章这么难呢? 关键是得找个新颖角度切入。 要是只在网上反复复制粘贴那些…...

WPF常见容器全方位介绍
Windows Presentation Foundation (WPF) 是微软的一种用于构建Windows桌面应用程序的UI框架。WPF的布局系统基于容器,帮助开发者以灵活、响应的方式组织用户界面 (UI) 元素。本篇文章将详细介绍WPF中几种常见的容器,包括Grid、StackPanel、WrapPanel、Do…...

重置时把el-tree树节点选中状态取消
要重置 Element UI 的 el-tree 组件并取消所有节点的选中状态,可以通过以下几种方法: 使用 setCheckedKeys 方法: 如果你的树配置了 node-key 属性,可以使用 setCheckedKeys 方法来清空所有选中的节点。 this.$refs.tree.setCheck…...

服务器系统克隆技术
工作任务:克隆对象是Windows server2019 和2022的datacenter版本 条件:在已经完成安装的虚拟机上做克隆 图1-1 用两个服务器的母盘准备进行克隆 第一步:新建一个文件目录用于安放克隆好的服务器 图1-2 创建两个目录用于安放即将克隆好的服务…...

【Java】多线程 Start() 与 run() (简洁实操)
Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容:三、问题描述start() 方法run() 方法 四、解决方案:4.1 重复调用 .run()4.2 重复调用 start()4.3 正常调用…...

基于微信小程序的购物系统【附源码、文档】
博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇dz…...

AI绘画:24最新Stable Diffusion 终极炼丹宝典:从入门到精通!
前言 我是咪咪酱,以浅显易懂的方式,与大家分享那些实实在在可行之宝藏。 历经耗时数十个小时,总算将这份Stable Diffusion的使用教程整理妥当。 从最初的安装与配置,细至界面功能的详解,再至实战案例的制作…...

线性可分支持向量机的原理推导【补充知识部分】拉格朗日函数 公式解析
本文是将文章《线性可分支持向量机的原理推导》中的公式单独拿出来做一个详细的解析,便于初学者更好的理解。在主文章中,有一个部分是关于补充拉格朗日对偶性的相关知识,此公式即为这部分内容。 公式 9-9 是关于拉格朗日函数 L ( x , α , β…...

csdn(最新交流群)
SEOI Chathttps://seoi.net/room/10122?kwe7cp45v此网站开放性较强,小心诈骗...

新手maven入门学习教程
MAVEN基础入门 提示:java新人的学习之路记录 学习内容: 提示:了解并会初步使用maven构建管理java项目 Maven 是一个非常流行的 Java 项目管理和构建工具。它通过提供一套标准的构建生命周期和一组预定义的目标来简化 Java 应用程序的构建过…...

React 中级阶段学习计划
React 中级阶段学习计划 目标 掌握状态管理和路由。能够调用API并处理异步数据。学会使用CSS-in-JS和CSS Modules进行样式处理。 学习内容 状态管理 React Context API Context API:用于在组件树中传递数据,避免多层props传递。示例:im…...

[产品管理-47]:产品市场调研 - 一级市场、二级市场、次级市场?
目录 一、产品销售环节的一级二级市场 1、一级市场 2、二级市场 3、一级市场与二级市场的互动关系 二、金融中的一级二级市场 1、一级市场(Primary Market)- 新股发行、定向发行 2、二级市场(Secondary Market)- 普通投资者…...

Linux零基础教程学习(黑马)
1.初识Linux 1.2远程连接Linux系统 图形化、命令行 对于操作系统的使用,有2种使用形式: 图形化页面使用操作系统 以命令的形式使用操作系统 不论是Windows还是Linux亦或是MacOS系统,都是支持这两种使用形式。 图形化:使用操作…...

一款零依赖、跨平台的流媒体协议处理工具,支持 RTSP、WebRTC、RTMP 等视频流协议的处理
大家好,今天给大家分享一款功能强大的流媒体协议处理工具go2rtc,支持多种协议和操作系统,具有零依赖、零配置、低延迟等特点。 项目介绍 go2rtc可以从各种来源获取流,包括 RTSP、WebRTC、HomeKit、FFmpeg、RTMP 等,并…...

PHP 正则验证A-Z且排除某字母
都已经找到这里来了,相信已经尝试很多办法了,那么我们直接上答案 关键正则:(?!.*[IO]) //验证5到6个大写字母且排除I和O if (preg_match(/^(?!.*[IO])[A-Z\d]{5,6}$/u, AAAAM)) {echo "匹配成功"; } else {echo "匹配失败…...

如何安全运行别人上传的Python代码?
写后端的同学,有时候需要在网站上实现一个功能,让用户上传或者编写自己的Python代码。后端再运行这些代码。 涉及到用户自己上传代码,我们第一个想到的问题,就是如何避免用户编写危险命令。如果用户的代码里面涉及到下面两行&…...

matlab相位图
% 清空工作空间和命令窗口 clear; clc; % 模拟生成时间t,位移y(t)和角位移theta(t) t linspace(0, 100, 1000); % 时间从0到100,包含1000个点 y 1e-5 * sin(2 * pi * 0.1 * t) .* exp(-0.01 * t); % 位移y(t) 振荡衰减 theta 1e-6 * cos(2 * pi * …...

C语言笔记(指针的进阶)
目录 1.字符指针 2.指针数组 3.数组指针 3.1.创建数组指针 3.2.&数组名和数组名 1.字符指针 int main() { char ch w;char* pc &ch;const char *p "abcdef";//常量字符串 产生的值就是首元素的地址//常量字符串不能被修改 因此需要加上一个…...
NodeJS连接MySQL 8.4报错:code: ‘ER_TABLEACCESS_DENIED_ERROR‘
NodeJS连接MySQL 8.4报错:code: ER_TABLEACCESS_DENIED_ERROR { code: ER_TABLEACCESS_DENIED_ERROR, errno: 1142, sqlMessage: "SELECT command denied to user 用户名localhost for table 表名", sqlState: 42000, index: 0, sql: SELECT …...

力扣66~70题
题66(简单): python代码: class Solution:def plusOne(self, digits: List[int]) -> List[int]:s_str.join([str(i) for i in digits])nstr(int(s_str)1)n_strlist(n)res[int(i) for i in n_str]return res题67(简…...

Axure重要元件三——中继器添加数据
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 本节课:中继器添加数据 课程内容:添加数据项、自动添加序号、自动添加数据汇总 应用场景:表单数据的添加 案例展示: 步骤…...

矩阵系统哪家好~矩阵短视频运营~怎么矩阵OEM
一、引言 在当今的数字化时代,矩阵系统在众多领域中发挥着至关重要的作用,如视频监控、信号切换、自动化控制等。然而,如何判断一个矩阵系统是否好用成为了许多用户面临的问题。本文将从多个方面探讨矩阵系统好用与否的判断标准,希…...

Axure树形菜单展开与折叠
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:Axure树形菜单展开与折叠 主要内容:树形菜单制作——层级关系——隐藏与显示——值的变化——多层交互 应用场景:关系树、菜…...

开发一个微信小程序要多少钱?
在当今数字化时代,微信小程序成为众多企业和个人拓展业务、提供服务的热门选择。那么,开发一个微信小程序究竟需要多少钱呢? 开发成本主要取决于多个因素。首先是功能需求的复杂程度。如果只是一个简单的信息展示小程序,功能仅限…...

AnaTraf | TCP重传的工作原理与优化方法
目录 什么是TCP重传? TCP重传的常见触发原因 TCP重传对网络性能的影响 1. 高延迟与重传 2. 吞吐量的下降 如何优化和减少TCP重传 1. 优化网络设备配置 2. 优化网络链路 3. 网络带宽的合理规划 4. 部署CDN和缓存策略 结语 AnaTraf 网络性能监控系统NPM | …...

python从0快速上手(一)python环境搭建 windows macos linux
Python环境搭建超详细指南 Python是一种广泛使用的高级编程语言,它以其简洁的语法和强大的功能而受到开发者的喜爱。对于初学者来说,搭建一个合适的Python开发环境是开始Python之旅的第一步。本文将为你提供一个超级详细的Python环境搭建指南࿰…...

麒麟aarch64架构下安装compat-openssl10
问题描述: 麒麟aarch64架构下安装mysql8.0.40,报错nothing provides libcrypto.so.10()(64bit) needed by 原因: 你当前系统的 OpenSSL 版本与 MySQL 8.0.40 所需的库不匹配。MySQL 8.0.40 需要 libcrypto.so.10,而你的系统使用的是 OpenS…...