一、背景说明

昨天一个同事让帮忙写个服务,用于接收并返回他那边提交过来的数据,以便其查看提交的数据及格式是否正确。

开始想用django写个接口,但写接口接口名称就得是定死的,他那边只能向这接口提交数据;接收一下就返回这种事情不如直接写个socket监听然后返回去。

以前也没怎么写正经的socket编程,基本是能收发点数据应差不多了,此次收发的数据一多就出了问题。

一是没接收完客户端要发送的数据就给客户端回RST,二是没发送完要给客户端发送的数据就又直接给客户端发送RST。

二、问题处理

2.1 tcp收发处理

使用s.recv()接收数据时,s.recv()只管从操作系统缓冲区中读取数据,阻塞模式下只要读到数据、非阻塞模式下不管读到读不到或者读到多少,函数都算执行完了程序会继续往后执行。因此接收大量数据时我们需要不断使用s.recv()进行读取然后设定一个终止标志。

使用s.send()发送数据时,s.send()只管通知操作系统发送数据,操作系统每次只是尽力发送数据然后把本次发送的数据作为返回值并不保证数据发送完成。因此在发送大量数据时我们需要不断使用s.send()发送然后设定一个终止标志。(不过如果单纯说python那可以使用snedall()函数来实现一次发送完,sendall()的实现方法和我们这里说的意思一样)

另外注意如果测试自己使用requests等作为客户端时,服务端的返回要加上http的响应头部,不然数据原样返回requests等进行解析会因不是一个正确的http响应而出错。

2.2 有问题程序

import socket# 获取本地主机名
host = socket.gethostname()
port = 9999# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口号
server_socket.bind((host, port))
# 设置最大连接数,超过后排队
server_socket.listen(5)# 这里实现的是接收客户端发来的数据、打印、然后再原样返回给客户端
while True:client_socket, addr = server_socket.accept()print(f"连接地址: {str(addr)}")# 错误二、当发来的数据很长时tcp不会等接收完成再执行下一条语句,这里没处理这个问题result = client_socket.recv(1024 * 1024)# 问题一、decode默认使用utf-8编码,但当发来的数据有utf-8不可解码内容时会报异常,这里没捕获异常print(f"{result.decode()}")# 错误三、发送时tcp不会等发送完再执行下一条语句,这里没处理这个问题
    client_socket.send(result)# 注意四、如果客户端中的接收代码是和上边错误二一样的,那么没发完也会被客户端resetclient_socket.close()

2.3 修正后程序

import socket# 获取本地主机名
host = socket.gethostname()
port = 9999# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口号
server_socket.bind((host, port))
# 设置最大连接数,超过后排队
server_socket.listen(5)
print("服务器程序已启动")while True:# 建立客户端连接client_socket, addr = server_socket.accept()# 阻塞模式,设置接收超时时长为1秒,1秒内没有新数据视为数据已传送完成client_socket.settimeout(1)# client_socket.setblocking(0)print(f"连接地址: {str(addr)}")# 这里result不能赋值为None,否则下边的result += tmp_result会因类型不一致报错# 这里result不能赋值为字符串"",否则下边的result += tmp_result会因类型不一致报错result = b""tmp_result = ""# 错误二修正:此处while循环用于确保接收完所有数据再执行后续指令while True:# 每次最多读取2048字节try:tmp_result = client_socket.recv(2048)# 1秒内无数据,触发超时异常,此时我们判定为数据已接收完成break退出# 不能使用获取数据为空作为退出标志,因为阻塞模式除非是已建立的网络连接被拆除不然读不到数据是不会返回的except socket.timeout as e:print(f"{e}")break# 将本次读取到的内容拼接到result中result += tmp_result# 问题一修正:对解码异常进行捕获,直接以byte形式输出try:print(f"{result.decode()}")except:print(f"{result}")total_lenght = result.__len__()print(f"\r\ntotal_length :{total_lenght}")flag = 0# 错误三修正:确保数据发送完才执行后续代码# python其实可以使用sendall()来完成,但sendall本身也是类似以下形式,为了通用性我们这里暂时不用while True:# 每次从已发送数据位置发送# 每次返回的是本次发送数据长度tmp_flag = client_socket.send(result[flag:])flag += tmp_flag# 如果已发送完则退出if flag == total_lenght:break# 至于问题四,客户端未完成接收即返回reset,那就只能由客户端去处理了client_socket.close()

参考:

https://stackoverflow.com/questions/34252273/what-is-the-difference-between-socket-send-and-socket-sendall

转载于:https://www.cnblogs.com/lsdb/p/10769090.html

Python3 Tcp未发送/接收完数据即被RST处理办法相关推荐

  1. 接收udp数据_聊聊UDP、TCP和实现一个简单的JAVA UDP小Demo

    最近真的比较忙,很久就想写了,可是一直苦于写点什么,今天脑袋灵光一闪,觉得自己再UDP方面还有些不了解的地方,所以要给自己扫盲. 好了,咱们进入今天的主题,先列一下提纲: 1. UDP是什么,UDP适 ...

  2. 网络编程中如何得知一次请求(或响应)的数据已接收完

    两年前用.net 2.0做了一个反向代理服务器,在这两年时间里,不断修改BUG以及优化性能,使得可用性大大提高.近来碰到一个功能需求,实在无法找出有效的解决办法,只好上来请教各位高人.     先说说 ...

  3. TCP发送和接收数据

    学习笔记--TCP发送和接收数据 TCP协议 三次握手 四次挥手 UDP协议介绍 TCP通信 TCP客户端构建流程 TCP服务端 TCP与UDP区别 socket之send和recv原理剖析 send ...

  4. PYTHON3 使用socket的接收数据包最大支持1460的简单处理方式

    1,本人小白一个,简单说下背景,这是在一个RFID读写器上进行的测试脚本开发,业务通信使用socket进行与产品的数据交互. 2,在实际通过网络助手测试中发现返回的数据量比较大,存在粘包的情况.并且接 ...

  5. bossGroup 接收完请求怎么推送到workGroup组的

    io.netty.bootstrap.ServerBootstrap.ServerBootstrapAcceptor channelPipleline默认会有一个headContext    --&g ...

  6. 【转】使用TCP协议连续传输大量数据时,是否会丢包,应如何避免?

    [转]使用TCP协议连续传输大量数据时,是否会丢包,应如何避免? Posted on 2008-06-11 15:24 路缘 阅读(3868) 评论(0) 编辑 收藏  http://www.cnbl ...

  7. 使用TCP协议连续传输大量数据时,是否会丢包,应如何避免

    使用TCP协议连续传输大量数据时,是否会丢包,应如何避免 这个问题看看似比较容易,但很多人有不同的理解.开发中遇到是否每包(包数据可能大于1460)发送完之后需要由server->client确 ...

  8. c语言网络定向拉取数据,用C模拟了一个http请求,但是recv函数接收的数据不完整且欠安顺序获取信息...

    用C模拟了一个http请求,但是recv函数接收的数据不完整且不安顺序获取信息 用C模拟了一个http请求,但是recv函数接收的数据不完整且不安顺序获取信息 我把代码贴上 #include #inc ...

  9. Hp-socket高性能网络库二--tcp组件pull接收模型

    一.定义 PULL 模型: 组件接收到数据时会触发监听器对象的 OnReceive(pSender, dwConnID,iTotalLength) 事件,告诉应用程序当前已经接收到多少数据,应用程序检 ...

最新文章

  1. 团队不需要在计划会上考虑到所有事情
  2. shell常用的基础命令
  3. CentOS在安装配置 Ngnix_tomcat_PHP_Mysql
  4. Redis--keys的通用操作
  5. 我的网页设计(网页页面制作二)
  6. python中实现定时器Timer
  7. dijkstra标号法表格_标号法求最短路径例题详解.ppt
  8. 计算机电子的危害,电子垃圾焚烧炉的危害有多大,你了解过吗?
  9. IOS UI 第一篇:基本UI
  10. Expression Blend4 中文
  11. 实习成长之路:MySQL十三: count(*)这么慢,我该怎么办?为什么那么慢?
  12. python 执行shell_python执行shell命令四法
  13. Fiori 实现在网页端调用摄像头扫描二维码进行识别
  14. windows环境搭建redis集群
  15. TexturePacker破解版教程及下载
  16. 郝斌数据结构-线性表之单链表程序(C语言版)
  17. 华为云obs对象存储使用教程
  18. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(5)- 语音识别实现(SpeechRecognition, PocketSphinx0.1.15)
  19. 【不忘初心】Windows11 22000.168 X64 四合一[纯净精简版][2.77G](2021.8.29)
  20. 微信小程序入门教程之四:API 使用

热门文章

  1. 对爬虫数据分析的同学不要错过啦 数据分析数据可视化: Matplotlib
  2. 开源 | CVPR 2021无需向量监督的矢量图生成算法
  3. 带你自学Python系列(九):一文读懂Python中字典应用原理!
  4. bit java实验2_2018-2019-2 20175120 实验五《Java网络编程》实验报告
  5. 卡卡半智能扫地机器人_扫地机器人哪个牌子好?精选五款高智能的扫地机器人...
  6. 大数据分析必须要会的python函数操作!!!
  7. 机器学习之分类性能度量指标 : ROC曲线、AUC值、正确率、召回率
  8. 深度学习(三十)贪婪深度字典学习
  9. mysql nhibernate_C#连接Mysql数据库NHibernate
  10. 多层陶瓷电容器用处_陶瓷电容器的用途有哪几种?