1. 单对单循环通信

​ send() 和recv()不是一一对应的。

# 服务端 server.py
import socket
phone = socket.socket() phone.bind = (('127.0.0.1', 8888)) # 绑定本地回环地址/端口号
phone.listen() # 开始监听
conn, addr = phone.accept() # 等待连接
print(f"连接{addr}成功!") while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data.upper() == b'Q': # 字节bytes Q
print('客户端已正常退出!')
break
print(f"来自客户端{addr}的消息:{from_client_data.decode('utf-8')}") to_server_data = input('>>>').strip().encode('utf-8')
phone.send(to_server_data)
except ConnectionResetError:
print('客户端连接中断!')
break
conn.close()
phone.close()
# 客户端 client.py

import socket

phone = socket.socket()
phone.connect(('127.0.0.1',8888)) while 1:
to_server_data = input('>>>').strip().encode('utf-8')
if not to_server_data:
print('输入内容不能为空!')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break
from_server_data = phone.recv(1024)
print(f"来自服务端的消息:{from_server_data.decode('utf-8')}") phone.close()

2. 循环连接通信:可连接多个客户端

# 服务端循环接收连接
import socket
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen()
while 1:
conn,addr = phone.accept() # 循环可接收客户端
print(f'与客户端{addr}连接成功!')
while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data.upper() == b'Q':
print('客户端已退出!')
break
print(f"来自客户端的消息:{from_client_data.decode('utf-8')}")
to_client_data = input('>>>').strip().encode('utf-8')
conn.send(to_client_data)
except ConnectionResetError:
print('客户端连接中断!')
break
conn.close()
phone.close()
# 客户端 client
import socket
phone = socket.socket()
phone.connect(('127.0.0.1',8848))
while 1:
to_server_data = input('>>>').strip().encode('utf-8')
if not to_server_data:
print('输入内容不能为空!')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break
from_server_data = phone.recv(1024)
print(f"来自服务端的消息:{from_server_data.decode('utf-8')}")
phone.close

3. 执行远程命令

# 使用subproess模块 可像操作系统cmd一样执行命令
import subprocess obj = subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) print(obj.stdout.read().decode('gbk')) # 正确命令
print(obj.stderr.read().decode('gbk')) # 错误命令
# 如果是正确的命令,那么错误命令会输出空字符。 # shell: 命令解释器,相当于调用cmd 执行指定的命令。
# stdout:正确结果丢到管道中。
# stderr:错了丢到另一个管道中。
# windows操作系统的默认编码是gbk编码。
# 在服务端 增加subprocess模块,

import subprocess
import socket phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.bind(('127.0.0.1', 8888)) phone.listen()
while 1:
conn, addr = phone.accept()
print(f'连接{addr}成功!')
while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data.upper() == b'Q':
print('客户端正常退出!')
break
# print(f"来自客户端{addr}的消息:{from_client_data.decode('utf-8')}")
obj = subprocess.Popen(from_client_data.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) to_client_data = obj.stdout.read() + obj.stderr.read()
# subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码
conn.send(to_client_data) # 此时是gbk的bytes的类型
except ConnectionResetError:
print('客户端连接中断!')
break
conn.close()
phone.close()
# 客户端 client
import socket phone = socket.socket()
phone.connect(('127.0.0.1', 8888)) while 1:
to_server_data = input('>>>').strip().encode('utf-8')
if not to_server_data:
print('输入内容不能为空!')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break from_server_data = phone.recv(1024)
print(f"{from_server_data.decode('gbk')}") # 需gbk解码 phone.close()

4. 粘包现象

4.1 socket缓冲区

​ 每个socket,都会有两个缓冲区,输入/输出缓冲区。过程如上图,send()结束后,会马上进入recv()状态(有阻塞)。

​ 作用:1. 暂时存储一些数据;2. 如果网络有波动,缓冲区会保护数据的收发稳定、匀速。

​ 缺点:是会造成粘包的现象之一。

4.2 出现粘包的情况:

​ 1. 如果客户端send() 数据超过recv() 设定的字节数,会先接收最大限制的字节数,当第二次send() 数据时,recv() 会将上次遗留的数据接收,产生粘包现象。

  1. 连续短暂send() 多次(数据量较小),数据会统一发送出去,产生粘包。

    (Nagle算法)

4.3 解决粘包现象

#思路:
服务端发出send() 数据有10000字节,客户端接收数据时,循环recv()接收,每次(至多)接收1024字节,直至将所有的字节全部接收完毕,将接收的数据拼接在一起,编码打印出。 #遇到的问题:
1. recv() 次数无法确定。
客户端先接收总数据的一个长度,然后再循环recv 控制循环次数,只有接收的数据长度 < 总数据长度,就会一直接收。(先发总数据长度,再发总数据)
2.获取总数据的长度是 int 类型,先要转换成 bytes 类型,再发出,但是总数据的长度转化成的 bytes类型的字节数是不固定的。
int:376 ——> str(376):'376' ——> bytes:b'376' (长度为3)
int:4558 ——> str(4558):'4558' ——> bytes:b'4558' (长度为4) 解决:将不固定长度的int类型转换成固定长度的bytes,并且还可以反解回来。(用来制定固定长度的报头)
# 将不固定长度的int类型转换成固定长度的bytes

import struct
ret = struct.pack('i',376) # 将int 376转换成固定4个长度的bytes字节
# i 默认长度为 4; q 默认为8
print(ret,type(ret),len(ret)) ret1 = struct.unpack('i',ret)[0] # 是元组形式, 反解成int型
print(ret1,type(ret1)) # 但是通过struct 处理不能处理太大数据
ret = struct.pack('l', 4323241232132324)
print(ret, type(ret), len(ret)) # 报错
# low版解决粘包现象

# 服务端server
import socket
import subprocess
import struct phone = socket.socket() phone.bind(('127.0.0.1',8888))
phone.listen() while 1:
conn, addr = phone.accept()
print(f'与客户端{addr}连接') while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data.upper() == b'Q':
print('客户端已退出!')
break
obj = subprocess.Popen(from_client_data.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
total_data = obj.stdout.read() + obj.stderr.read() conn.send(struct.pack('i', len(total_data))) # 发出 总数据长度的bytes类型
print(len(total_data))
conn.send(total_data) # 发出总数据 gbk编码的字节
except ConnectionResetError:
print('与客户端连接中断!')
break
conn.close()
phone.close()
# 客户端client

import socket
import struct phone = socket.socket() phone.connect(('127.0.0.1', 8888)) while 1: to_server_data = input('>>>').strip().encode('utf-8')
if not to_server_data:
print('内容不能为空!')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break head_bytes = phone.recv(4) # 接收总数据长度的bytes
head_int = struct.unpack('i', head_bytes)[0] # 反解成int
print(head_int)
data = b'' # 定义一个空字节
while len(data) < head_int:
data = data + phone.recv(1024) print(len(data))
print(f"{data.decode('gbk')}") # 终端是 gbk 编码的 phone.close()

bytes

​ 用于网络传输、文件存储时。

能够保持数据原本类型。

python 30 基于TCP协议的socket通信的更多相关文章

  1. 基于TCP协议的socket通信

    一.服务器端 1.创建serverSocket,即服务器端的socket,绑定指定的端口,并侦听此端口 ServerSocket server = new ServerSocket(8888); 2. ...

  2. 基于TCP 协议的socket 简单通信

    DNS 服务器:域名解析 socket 套接字 : ​ socket 是处于应用层与传输层之间的抽象层,也是一组操作起来非常简单的接口(接受数据),此接口接受数据之后,交由操作系统 为什么存在 soc ...

  3. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  4. day31——recv工作原理、高大上版解决粘包方式、基于UDP协议的socket通信

    day31 recv工作原理 源码解释: Receive up to buffersize bytes from the socket. 接收来自socket缓冲区的字节数据, For the opt ...

  5. python中基于tcp协议的通信(数据传输)

    tcp协议:流式协议(以数据流的形式通信传输).安全协议(收发信息都需收到确认信息才能完成收发,是一种双向通道的通信) tcp协议在OSI七层协议中属于传输层,它上承用户层的数据收发,下启网络层.数据 ...

  6. Java:基于TCP协议网络socket编程(实现C/S通信)

    目录 一.前言:TCP原理简介 二.Socket编程通信 三.TCP服务器端(具体代码) 四.TCP客户端(具体代码) 五.通信效果演示 六."创意"机器人:价值一个亿的AI核心代 ...

  7. 基于TCP协议的socket套接字编程

    目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...

  8. 浅析C#基于TCP协议的SCOKET通信

    TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实 ...

  9. 网络编程: 基于TCP协议的socket, 实现一对一, 一对多通信

    TCP协议  面向连接 可靠的 面向字节流形式的 tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 TCP协议编码流程: 服务器端:                 客户端 实例化对 ...

随机推荐

  1. [剑指offer] 46. 孩子们的游戏(圆圈中最后剩下的数)

    题目描述 随机指定一个数m,让编号为0的小朋友开始报数.每次喊到m-1的那个小朋友要出列,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友 ...

  2. .gitignore文件我自己常用的配置

    我项目中一般不需要上传到git服务器上的有 .idea ------.idea目录 .mvn ------.mvn目录 .iml mvnw mvnw.cmd logs/ --- 我生成的日志文件目录 ...

  3. 从零开始react实战:云书签-1 react环境搭建

    总览篇:react 实战之云书签 本篇是实战系列的第一篇,主要是搭建 react 开发环境,在create-react-app的基础上加上如下功能: antd 组件库按需引入 ,支持主题定制 支持 l ...

  4. Spring Boot中自定义注解+AOP实现主备库切换

    摘要: 本篇文章的场景是做调度中心和监控中心时的需求,后端使用TDDL实现分表分库,需求:实现关键业务的查询监控,当用Mybatis查询数据时需要从主库切换到备库或者直接连到备库上查询,从而减小主库的 ...

  5. win10家庭版打开组策略

    新建记事本,输入: @echo off pushd "%~dp0" dir /b C:\Windows\servicing\Packages\Microsoft-Windows-G ...

  6. Superset 官方入门教程中文翻译

    本文翻译自 Superset 的官方文档:Toturial - Creating your first dashboard 最新版本的 Superset 界面与功能上与文档中提到的会有些许出入,以实际 ...

  7. solr 新建core

    D:\tomcat\webapps\solr\solr_home 在该路径下创建一个新的core,所需文件和层级如下 test_core |-- conf |-- schema.xml |-- sol ...

  8. Git 学习笔记之(一) 使用 git gui 从github上下载代码

    背景: 目前一些开源代码均在 GitHub上管理的,包括自己写的代码也可以放在上面进行管理.但问题是,当你换一台电脑,想要将你自己放在 GitHub 上的代码工程下载下来的时候,会遇到各种问题,目前可 ...

  9. go interface衍生的插件化处理

    在设计程序的许多应用场景中我们会遇到大体分为三个阶段的任务流. 第一.入口 一个或多个入口,等待阻塞的.或者主动请求方式的. ============================== 比如任务流需 ...

  10. React 基于antd+video.js实现m3u8格式视频播放及实时切换

    文档连接地址(官网看起麻烦,看中文别人整理好的)https://blog.csdn.net/a0405221/article/details/80923090 React项目使用  安装依赖 npm ...