socket补充:通信循环、链接循环、远程操作及黏包现象

socket补充:通信循环、链接循环、远程操作及黏包现象

socket通信循环

server端:

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8080))phone.listen(5)conn, client_addr = phone.accept()
print(conn, client_addr, sep='\n')while 1:  # 循环收发消息try:from_client_data = conn.recv(1024)print(from_client_data.decode('utf-8'))conn.send(from_client_data + b'SB')except ConnectionResetError:breakconn.close()
phone.close()

client端:

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 买电话phone.connect(('127.0.0.1',8080))  # 与客户端建立连接, 拨号while 1:  # 循环收发消息client_data = input('>>>')phone.send(client_data.encode('utf-8'))from_server_data = phone.recv(1024)print(from_server_data.decode('utf-8'))phone.close()  # 挂电话

socket通信链接循环

server端:

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8080))phone.listen(5)while 1 : # 循环连接客户端conn, client_addr = phone.accept()print(client_addr)while 1:try:from_client_data = conn.recv(1024)print(from_client_data.decode('utf-8'))conn.send(from_client_data + b'SB')except ConnectionResetError:breakconn.close()
phone.close()

服务端:

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 买电话phone.connect(('127.0.0.1',8080))  # 与客户端建立连接, 拨号while 1:client_data = input('>>>')phone.send(client_data.encode('utf-8'))from_server_data = phone.recv(1024)print(from_server_data.decode('utf-8'))phone.close()  # 挂电话

socket远程操作

import subprocessobj = subprocess.Popen('dir1',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)print(obj.stdout.read().decode('gbk'))  # 正确命令
print(obj.stderr.read().decode('gbk'))  # 错误命令

服务端:

import socket
import subprocess
phone = socket.socket()phone.bind(('127.0.0.1',8848))phone.listen(2)
# listen: 2 允许有两个客户端加到半链接池,超过两个则会报错while 1:conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中print(f'链接来了: {conn,addr}')while 1:try:from_client_data = conn.recv(1024)  # 最多接受1024字节if from_client_data.upper() == b'Q':print('客户端正常退出聊天了')breakobj = subprocess.Popen(from_client_data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)result = obj.stdout.read() + obj.stderr.read()conn.send(result)except ConnectionResetError:print('客户端链接中断了')breakconn.close()
phone.close()# shell: 命令解释器,相当于调用cmd 执行指定的命令。
# stdout:正确结果丢到管道中。
# stderr:错了丢到另一个管道中。
# windows操作系统的默认编码是gbk编码。

客户端:

import socketphone = socket.socket()phone.connect(('127.0.0.1',8848))
while 1:to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')if not to_server_data:# 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送print('发送内容不能为空')continuephone.send(to_server_data)if to_server_data.upper() == b'Q':breakfrom_server_data = phone.recv(1024)  # 最多接受1024字节print(f'{from_server_data.decode("gbk")}')phone.close()

什么叫做黏包现象?为什么会出现黏包现象?

socket收发消息的原理

1729998-20190816152859172-18357743.png

应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。

而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的。怎样定义消息呢?

可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

设置缓冲区的两个好处:

  1. 暂时存储一些数据.
  2. 缓冲区存在如果你的网络波动,保证数据的收发稳定,匀速.

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

只有TCP有粘包现象,UDP永远不会粘包

黏包的两种情况:

1,接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

server端:

import socket
import subprocessphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)phone.bind(('127.0.0.1', 8080))phone.listen(5)while 1:  # 循环连接客户端conn, client_addr = phone.accept()print(client_addr)while 1:try:cmd = conn.recv(1024)ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)correct_msg = ret.stdout.read()error_msg = ret.stderr.read()conn.send(correct_msg + error_msg)except ConnectionResetError:breakconn.close()
phone.close()

client端:

import socketphone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 买电话phone.connect(('127.0.0.1',8080))  # 与客户端建立连接, 拨号while 1:cmd = input('>>>')phone.send(cmd.encode('utf-8'))from_server_data = phone.recv(1024)print(from_server_data.decode('gbk'))phone.close()

2、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包)

server端:

import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)phone.bind(('127.0.0.1', 8080))phone.listen(5)conn, client_addr = phone.accept()frist_data = conn.recv(1024)
print('1:',frist_data.decode('utf-8'))  # 1: helloworld
second_data = conn.recv(1024)
print('2:',second_data.decode('utf-8'))conn.close()
phone.close()

客户端:

import socketphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  phone.connect(('127.0.0.1', 8080)) phone.send(b'hello')
phone.send(b'world')phone.close()  # 两次返送信息时间间隔太短,数据小,造成服务端一次收取

如何解决黏包现象?

struct模块

该模块可以把一个类型,如数字,转成固定长度的bytes

1729998-20190816152911745-450888539.jpg

import struct
# 将一个数字转化成等长度的bytes类型。
ret = struct.pack('i', 183346)
print(ret, type(ret), len(ret))# 通过unpack反解回来
ret1 = struct.unpack('i',ret)[0]
print(ret1, type(ret1), len(ret1))# 但是通过struct 处理不能处理太大ret = struct.pack('l', 4323241232132324)
print(ret, type(ret), len(ret))  # 报错

方案一:low版。

  问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总数按照固定字节发送给接收端后面跟上总数据,然后接收端先接收固定字节的总字节流,再来一个死循环接收完所有数据。

server端:

import socket
import subprocess
import struct
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)phone.bind(('127.0.0.1', 8080))phone.listen(5)while 1:conn, client_addr = phone.accept()print(client_addr)while 1:try:cmd = conn.recv(1024)ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)correct_msg = ret.stdout.read()error_msg = ret.stderr.read()# 1 制作固定报头total_size = len(correct_msg) + len(error_msg)header = struct.pack('i', total_size)# 2 发送报头conn.send(header)# 发送真实数据:conn.send(correct_msg)conn.send(error_msg)except ConnectionResetError:breakconn.close()
phone.close()

client端:

import socket
import struct
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8080))while 1:cmd = input('>>>').strip()if not cmd: continuephone.send(cmd.encode('utf-8'))# 1,接收固定报头header = phone.recv(4)# 2,解析报头total_size = struct.unpack('i', header)[0]# 3,根据报头信息,接收真实数据recv_size = 0res = b''while recv_size < total_size:recv_data = phone.recv(1024)res += recv_datarecv_size += len(recv_data)print(res.decode('gbk'))phone.close()

转载于:https://www.cnblogs.com/lifangzheng/p/11364213.html

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

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

相关文章

PCA的原理及MATLAB实现

相关文章 PCA的原理及MATLAB实现 UFLDL教程&#xff1a;Exercise:PCA in 2D & PCA and Whitening python-A comparison of various Robust PCA implementations &#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&a…

Java生鲜电商平台-SpringCloud微服务架构中核心要点和实现原理

Java生鲜电商平台-SpringCloud微服务架构中核心要点和实现原理 说明&#xff1a;Java生鲜电商平台中&#xff0c;我们将进一步理解微服务架构的核心要点和实现原理&#xff0c;为读者的实践提供微服务的设计模式&#xff0c;以期让微服务在读者正在工作的项目中起到积极的作用。…

iOS中下载小文件

在iOS中通过网络下载小文件比如小型图片等资源&#xff0c;一般在子线程中将数据完全下载完毕&#xff0c;然后在调用block将下载的数据整个部分返回&#xff0c;或者采用同步返回下载数据。 一般采用以下两种方式&#xff1a; &#xff08;1&#xff09;使用GCD将下载操作放…

iOS下载大文件原理解析一

iOS中下载大型文件&#xff0c;需要考虑到占用内存的大小与下载速度&#xff08;使用多线程&#xff09;&#xff0c;因此本文首先介绍一个原理性下载文件的DEMO。 在下载大型文件中&#xff0c;需要知道下载的进度因此需要使用代理模式&#xff0c;不断的回调下载进度。 - (…

recv原理、高阶版黏包解决方案、基于UDP的socket通信

recv原理、高阶版黏包解决方案、基于UDP的socket通信 recv原理 源码解释&#xff1a; Receive up to buffersize bytes from the socket. 接收来自socket缓冲区的字节数据&#xff0c; For the optional flags argument, see the Unix manual. 对于这些设置的参数&#xff0c;可…

iOS中下载大型文件的原理解析二

在iOS中下载大型文件&#xff0c;需要使用NSURLConnection 的代理方法&#xff1a; (void)touchesBegan:(NSSet)touches withEvent:(UIEvent *)event { NSURL *url [NSURL URLWithString:”http://d.3987.com/fengj_141112/007.jpg“]; NSURLRequest *request [NSURLReque…

ASP.NET Core Web 应用程序开发期间部署到IIS自定义主机域名并附加到进程调试

想必大家之前在进行ASP.NET Web 应用程序开发期间都有用到过将我们的网站部署到IIS自定义主机域名并附加到进程进行调试。 那我们的ASP.NET Core Web 应用程序又是如何部署到我们的IIS上面进行调试的呢&#xff0c;接下来我们来简单介绍下&#xff1a; 一、安装IIS所需的Host扩…

iOS下载大型文件原理解析三

在下载大型文件过程中是可以取消下载的 - (IBAction)download:(UIButton *)sender { // 状态取反 sender.selected !sender.isSelected; // 断点续传 // 断点下载if (sender.selected) { // 继续&#xff08;开始&#xff09;下载// 1.URLNSURL *url [NSURL URLWithStrin…

HTML文件上传与下载

文件下载 传统的文件下载有两种方法&#xff1a; 使用<a/>标签&#xff0c;href属性直接连接到服务器的文件路径window.location.href"url"这两种方法效果一样。但有个很大的问题&#xff0c;如果下载出现异常&#xff08;连接路径失效、文件不存在、网络问题等…

NSURLSession的应用

iOS7以后发布了NSURLSession用来替换NSURLConnection&#xff0c;NSURLSession使用方式有以下两种&#xff1a; 1.block方式 &#xff08;1&#xff09;创建的步骤 获取单例会话对象 创建URL对象 隐含创建request 创建NSURLSessionDataTask // 1.获取会话对象 NSURLSess…

ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)...

在正式进入主题之前我们来看下几个概念&#xff1a; 一、依赖倒置 依赖倒置是编程五大原则之一&#xff0c;即&#xff1a; 1、上层模块不应该依赖于下层模块&#xff0c;它们共同依赖于一个抽象。 2、抽象不能依赖于具体&#xff0c;具体依赖于抽象。 其中上层就是指使用者&am…

iOS中XML解析

iOS中XML解析分为两种实现方式&#xff1a;SAX与DOM SAX方式&#xff1a;主要是事件驱动的解析方式&#xff0c;是逐行读取XML数据&#xff0c;不断回调代理&#xff0c;告诉代理当前解析的元素开始或者结束。 DOM解析方式&#xff1a;是讲整个XML数据全部读入内存&#xff0…

苹果电脑基本设置+Linux 命令+Android 实战集锦

本文微信公众号「AndroidTraveler」首发。 背景 大多数应届毕业生在大学期间使用的比较多的是 windows 电脑&#xff0c;因此初入职场如果拿到一台苹果电脑&#xff0c;可能一时间不能够很快的上手。基于此&#xff0c;这边出了系列视频&#xff0c;通过实际的演示让没使用过苹…

iOS中POST请求

iOS中POST请求的发送需要使用NSMutableURLRequest可以设置URL request的头字段&#xff0c;比如超时时间&#xff0c;请求类型&#xff1a;GET POST等一些关键头字段&#xff1a; - (IBAction)login { // 1.用户名 NSString *usernameText self.username.text; if (userna…

发送JSON数据给服务器

需要将JSON格式的数据传送给服务器&#xff0c;注意需要设置&#xff1a; [request setValue:”application/json” forHTTPHeaderField:”Content-Type”]; Content-Type类型为&#xff1a;application/json // 1.URL NSURL *url [NSURL URLWithString:"http://localh…

Mac中AndroidStudio没有找到Plugins的问题

我们在windows中都可以正常找到plugins 但是在Mac上AndroidStudio里 setting打开却没有plugins 正准备在Mac上搞一下flutter呢 我感觉智商受到了侮辱&#xff01; 这里其实是mac版本给我开了个玩笑 你可以按快捷键&#xff0c;你就可以找到 快捷键 command ‘,’ 没错就是comm…

进程和操作系统概述

进程和操作系统概述 进程的基础 程序和进程&#xff1a; 程序是一对静态的代码文件 进程是一个正在运行着的程序&#xff0c;抽象概念 进程由操作系统操控调用交于CPU运行 操作系统 1.管理控制协调计算机硬件和软件的关系 2.操作系统的作用&#xff1f; ​ 第一个作用&#xff…

iOS手势操作简介(一)

iOS中能够响应手势操作的类必须要继承自UIResponder&#xff0c;才能够处理手势响应操作。 默认继承了UIResponder的类有&#xff1a;UIApplication UIViewController UIView都继承自UIResponder. UIView是UIResponder的子类&#xff0c;可以实现下列4个方法处理不同的触摸事…

iOS开发中手势处理简介(二)

iOS中手势操作事件的产生于传递 发生触摸事件后&#xff0c;系统会将该事件加入到一个由UIApplication管理的事件队列中 UIApplication会从事件队列中取出最前面的事件&#xff0c;并将事件分发下去以便处理&#xff0c;通常&#xff0c;先发送事件给应用程序的主窗口&#x…

对前端Jenkins自动化部署的研究

1. 安装 安装 Nginx 1.1去官网下直接下载&#xff0c;解压缩 start nginx就可以使了&#xff0c;常用命令&#xff1a; start nginx # 启动 nginx -s reload # 修改配置后重新加载生效 nginx -s reopen # 重新打开日志文件 nginx -t # 配置文件检测是否正确 1.2 安装Jenkins…