网络通信与并发编程(二)基于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协议会帮你封装上消息头。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/451548.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java】多线程 Start() 与 run() (简洁实操)

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

基础数据结构——链表(单向链表,双向链表,循环链表)

1.概述 在计算机科学中,链表是数据元素的线性集合,其每个元素都指向下一个元素,元素存储上并不连续 分类 单向链表,每个元素只知道其下一个元素是谁 双向链表,每个元素知道其上一个元素和下一个元素 循环链表&am…

EasyExcel填充模板导出excel.xlsx

菜鸟的自我救赎,自从有了GPT,还是头一次一个bug写一天。 直接贴导出excel模板的完整案例 官网冲刺 EasyExcel EasyExcel填充模板导出excel.xlsx / 导出excel模板 一、bug(不需要请跳过) 1.1 使用apache poi操作excel报错 java.lang.NoSuchMethodError…

与双指针的亲密接触:快与慢的浪漫交错

公主请阅 1.合并两个有序数组1.1 题目说明示例 1示例 2示例 3 1.2 题目分析 1.3代码部分1.4 代码解析 2.移动零2.1题目说明示例 1示例 2 2.2题目分析2.3代码部分2.4代码解析 1.合并两个有序数组 题目传送门 1.1 题目说明 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums…

汽车免拆诊断案例 | 2022款大众捷达VS5车行驶中挡位偶尔会锁在D3挡

故障现象  一辆2022款大众捷达VS5汽车,搭载EA211发动机和手自一体变速器,累计行驶里程约为4.5万km。该车行驶中挡位偶尔会锁在D3挡,车速最高约50 km/h,且组合仪表上的发动机故障灯和EPC灯异常点亮。 故障诊断  用故障检测仪检…

linux一二三章那些是重点呢

第一章 静态库动态库的区别 什么是库 库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接 拿来用的变量、函数或类。 如何制作 静态动态库 静态库: GCC 进行链接时,会把静态库中代码打…

MySQL-15.DQL-分页查询

一.DQL-分页查询 -- 分页查询 -- 1. 从 起始索引0 开始查询员工数据,每页展示5条记录 select * from tb_emp limit 0,5; -- 2.查询 第1页 员工数据,每页展示5条记录 select * from tb_emp limit 0,5; -- 3.查询 第2页 员工数据,每页展示5条记…

Golang | Leetcode Golang题解之第491题非递减子序列

题目: 题解: var (temp []intans [][]int )func findSubsequences(nums []int) [][]int {ans [][]int{}dfs(0, math.MinInt32, nums)return ans }func dfs(cur, last int, nums []int) {if cur len(nums) {if len(temp) > 2 {t : make([]int, len(…

4.计算机网络_TCP

可靠与效率 TCP的主要特点: TCP是面向连接的运输层协议,每一条TCP连接只能有两个端点,即:点对点、一对一形式。每一个端口都是一个socket。TCP提供可靠交付的服务TCP提供全双工通信,因为TCP的收发缓冲区是分开的。TC…

java导出带图形的word

先看效果图:方法都是一样的,所以数据只做了前两组 第一步需要准备模版: 新建一个word插入图表,选择想要的图表。 编辑图表:营业额表示数字,季度表示文字。其他的样式编辑可根据自己的需求更改,…

(42)MATLAB中使用fftshift绘制以零为中心的功率谱

文章目录 前言一、MATLAB代码二、仿真结果画图 前言 在分析信号的频率分量时,将零频分量平移到频谱中心会很有帮助。本例给出绘制以零为中心的功率谱的方法。 一、MATLAB代码 代码如下: f 1; % 余弦波的振荡频率&#xf…

400行程序写一个实时操作系统(十):用面向对象思想构建抢占式内核

前言 通过前几章的学习,我们学会了如何为RTOS设计一个合理的内存管理算法。现在,是时候学习设计RTOS内核了。 关于RTOS内核的文章也有很多,但都有一点先射箭再化靶子的意味。要么是代码连篇解释却寥寥无几,要么是要先怎么样再怎么…

大数据linux操作系统

第一关:Linux的初体验 答案: cd / ls -a / (里面有空格要注意) 第二关:Linux的常用命令 答案: touch newfile mkdir newdir cp newfile newdir/newfileCpy 第三关:Linux查询命令帮助语句…

飞机大战告尾

参考 PPO算法逐行代码详解 链接 通过网盘分享的文件:PlaneWar 链接: https://pan.baidu.com/s/1cbLKTcBxL6Aem3WkyDtPzg?pwd1234 提取码: 1234 10.17关于博客发了又改这件事 悲催的事 今天训练了一早上ppo模型,满怀期待的检测成果时发现一点长进都…

根据语音生成视频33搜帧

33搜帧,是一个能根据语音生成视频的网站,33搜帧 - 视频帧画面搜索引擎 33搜帧是一个使用AI技术构建的视频帧画面搜索引擎,和一般素材平台通过视频标签来搜索视频不同,33搜帧能搜索到视频素材中的每一帧画面,这个功能可…

基于SpringBoot+Vue+uniapp的海产品加工销售一体化管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的视频演示 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不…

软考(网工)——网络操作系统与应用服务器

文章目录 网络操作系统与应用服务器🕐本地用户与组1️⃣Windows server 2008R2 本地用户与组2️⃣常见用户组与权限 🕑活动目录1️⃣活动目录2️⃣活动目录(Active Directory,AD)3️⃣活动目录工作组分类 🕒远程桌面与…

uniapp学习(005-1 详解Part.1)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战,开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第36p-第p40的内容 文章目录 响应式尺寸单位 rpx各种工具修改ui给的图片的宽度ps操作步骤即时设计操作步骤&…

高级算法设计与分析 学习笔记13 线性规划

注意是线性规划不是动态规划哦 好家伙,这不是凸优化吗? 凸优化标准形式: 先改成统一最大化(凸优化那边怎么是统一最小化?) 原来的x2正负无所谓,但我希望每个x都是有限制的,所以把它改…

高德开放平台API调用实战指南

本文 一、地图展示1.1 地图初始化与展示1.2 自定义标记 二、路线规划2.1 驾车路线规划2.2 步行路线规划 三、定位服务3.1 使用JavaScript API进行定位3.2 IP定位 四、实时交通信息查询4.1 获取实时交通路况 五、智能调度引擎总结 一、地图展示 地图展示是开发基于地理信息系统…