粘包现象两种

    登陆

#服务端
import json
import socket server=socket.socket()#创建socket对象
ip_port=('127.0.0.1',8001)#获取本机回环地址和通信端口号 server.bind(ip_port)#绑定ip地址和端口号
#设置用户名和密码
username='alex'
password='' server.listen()#监听服务端口号
conn,addr=server.accept() while 1:
'''
from_client_msg接受客户端的用户信息
user_info_dict=json.loads(from_client_msg)接受用户信息转换成字典
'''
from_client_msg=conn.recv(1024).decode('utf-8') user_info_dict=json.loads(from_client_msg)
print(user_info_dict)
if username==user_info_dict['username'] and password ==user_info_dict['password']:
#设定200是登陆成功的状态码
conn.send(b'')
break
else:
# 设定250是登陆失败的状态码
conn.send(b'')
conn.close()
server.close()
#客户端
import json
import socket
client=socket.socket() #创建socket套接字对象
ip_port=('127.0.0.1',8001)#获取ip地址和端口号
client.connect(ip_port)#客户端连接IP地址 while 1:
#让用户输入用户名和密码
uname=input("请输入用户名:").strip()
pwd=input("请输入密码:").strip()
#定义一个字典来存储用户登陆信息
user_info={'username':uname,'password':pwd}
'''
因为send的数据类型必须是bytes类型,所有需要将字典转换为bytes类型,
但是字典无法直接转换成bytes,所以我们使用json序列化,先转换成str
'''
user_info_json=json.dumps(user_info)
user_info_str=user_info_json.encode('utf-8')
# 客户端发送信息
client.send(user_info_str)
#接收到服务端的返回信息
from_server_data=client.recv(1024).decode('utf-8')
if from_server_data=='':
print('登陆成功')
break
else:
print('用户名或密码错误')
client.close()

一.连续的小包,会被优化机制给合并,代码如下

服务端:

import socket
server=socket.socket()
ip_port=('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr=server.accept()
from_client_msg1=conn.recv(1024).decode('utf-8')
from_client_msg2=conn.recv(1024).decode('utf-8')
print('from_client_msg1>>>',from_client_msg1)

客户端:

import socket
client=socket.socket()
ip_port=('127.0.0.1',8001)
client.connect(ip_port)
client.send(b'12')
client.send(b'22')

  

解决方案

服务端代码如下

import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024).decode('utf-8') sub_obj = subprocess.Popen(
from_client_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#subprocess对象.read 得到的结果是bytes类型的
cmd_res = sub_obj.stdout.read()
data_len = len(cmd_res)
data_len_str = str(data_len)
print('结果长度>>>',data_len) conn.send(data_len_str.encode('utf-8'))
client_stutas = conn.recv(1024).decode('utf-8')
if client_stutas == 'ok': conn.send(cmd_res)
else:
print('客户端长度信息没有收到')

  客户端代码如下

import json
import socket client = socket.socket()
ip_port = ('127.0.0.1',8001)
client.connect(ip_port) while 1:
client_cmd = input('请输入系统指令>>>')
client.send(client_cmd.encode('utf-8'))
from_server_datalen = client.recv(1024).decode('utf-8') client.send(b'ok') from_server_result = client.recv(int(from_server_datalen)) print(from_server_result.decode('gbk'))

二.服务端一次性无法完全就收完客户端发送的数据,第二再次接收的时候,会接收到第一次遗留的内容

服务端

import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024).decode('utf-8') sub_obj = subprocess.Popen(
from_client_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#subprocess对象.read 得到的结果是bytes类型的
cmd_res = sub_obj.stdout.read()
print('结果长度>>>',len(cmd_res))
conn.send(cmd_res)

  客户端

import json
import socket client = socket.socket()
ip_port = ('127.0.0.1',8001)
client.connect(ip_port) while 1:
client_cmd = input('请输入系统指令>>>')
client.send(client_cmd.encode('utf-8')) from_server_result = client.recv(1024) print(from_server_result.decode('gbk'))

  运行代码试试

三,针对数据量大的粘包现象解决方案

服务端代码如下

import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
data_full_len = 0 #统计发送数据的长度
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024).decode('utf-8') sub_obj = subprocess.Popen(
from_client_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#subprocess对象.read 得到的结果是bytes类型的
cmd_res = sub_obj.stdout.read()
data_len = len(cmd_res) #总数据长度
data_len_str = str(data_len)
print('结果长度>>>',data_len) conn.send(data_len_str.encode('utf-8'))
client_stutas = conn.recv(1024).decode('utf-8') if client_stutas == 'ok':
#发送真实数据
while data_full_len < data_len:
every_send_data = cmd_res[data_full_len:data_full_len + 1024]
every_send_datalen = len(every_send_data)
conn.send(every_send_data)
data_full_len += 1024 else:
print('客户端长度信息没有收到')

  客户端代码如下

import json
import socket client = socket.socket()
ip_port = ('127.0.0.1',8001)
client.connect(ip_port)
all_recv_len = 0
all_data_byte = b'' while 1:
client_cmd = input('请输入系统指令>>>')
client.send(client_cmd.encode('utf-8'))
from_server_datalen = client.recv(1024).decode('utf-8')
all_data_len = int(from_server_datalen) #服务端发送的总数据长度 client.send(b'ok') while all_recv_len < all_data_len: from_server_result = client.recv(1024)
every_recv_len = len(from_server_result) #每次接受的数据长度
all_recv_len += every_recv_len
all_data_byte += from_server_result print(all_data_byte.decode('gbk'))

  2是struct模块解决粘包现象

通过struct模块,将要发送的真实数据的长度进行打包,打包成4个字节,和真实数据一起一次性发送个客户端.客户端取出前4个字节,通过struct解包获得后面真实数据的长度,根据这个长度再进行数据的接受

服务端代码如下

import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001)
data_full_len = 0 #统计发送数据的长度
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024).decode('utf-8') sub_obj = subprocess.Popen(
from_client_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#subprocess对象.read 得到的结果是bytes类型的
cmd_res = sub_obj.stdout.read()
data_len = len(cmd_res) #总数据长度
data_len_str = str(data_len)
print('结果长度>>>',data_len) #将真实数据长度打包成4个字节的数据
struct_data_len = struct.pack('i',data_len) conn.send(struct_data_len + cmd_res)

  客户端代码如下

import json
import socket
import struct
client = socket.socket()
ip_port = ('127.0.0.1',8001)
client.connect(ip_port)
all_recv_len = 0
all_data_byte = b'' while 1:
client_cmd = input('请输入系统指令>>>')
client.send(client_cmd.encode('utf-8'))
#先接收4个字节,这4个字节是真实数据长度加工成的
recv_data_len = client.recv(4)
#将4个字节长度的数据,解包成后面真实数据的长度
real_data_len = struct.unpack('i',recv_data_len)[0] print(real_data_len) server_result = client.recv(real_data_len) print(server_result.decode('gbk'))

    

四获取缓冲区的方法

import socket
from socket import SOL_SOCKET,SO_REUSEADDR,SO_SNDBUF,SO_RCVBUF
sk = socket.socket(type=socket.SOCK_DGRAM)
# sk.setsockopt(SOL_SOCKET,SO_RCVBUF,80*1024)
sk.bind(('127.0.0.1',8090))
print('>>>>', (sk.getsockopt(SOL_SOCKET, SO_SNDBUF))/1024)
print('>>>>', sk.getsockopt(SOL_SOCKET, SO_RCVBUF))

  

五.合法性连接验证

服务端代码如下

from socket import *
import hmac,os secret_key=b'Jedan has a big key!'
def conn_auth(conn):
'''
认证客户端链接
:param conn:
:return:
'''
print('开始验证新链接的合法性')
msg=os.urandom(32)#生成一个32字节的随机字符串
conn.sendall(msg)
h=hmac.new(secret_key,msg)
digest=h.digest()
respone=conn.recv(len(digest))
return hmac.compare_digest(respone,digest) def data_handler(conn,bufsize=1024):
if not conn_auth(conn):
print('该链接不合法,关闭')
conn.close()
return
print('链接合法,开始通信')
while True:
data=conn.recv(bufsize)
if not data:break
conn.sendall(data.upper()) def server_handler(ip_port,bufsize,backlog=5):
'''
只处理链接
:param ip_port:
:return:
'''
tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(backlog)
while True:
conn,addr=tcp_socket_server.accept()
print('新连接[%s:%s]' %(addr[0],addr[1]))
data_handler(conn,bufsize) if __name__ == '__main__':
ip_port=('127.0.0.1',9999)
bufsize=1024
server_handler(ip_port,bufsize)

  客户端代码如下

from socket import *
import hmac,os secret_key=b'Jedan has a big key!'
def conn_auth(conn):
'''
验证客户端到服务器的链接
:param conn:
:return:
'''
msg=conn.recv(32)
h=hmac.new(secret_key,msg)
digest=h.digest()
conn.sendall(digest) def client_handler(ip_port,bufsize=1024):
tcp_socket_client=socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while True:
data=input('>>: ').strip()
if not data:continue
if data == 'quit':break tcp_socket_client.sendall(data.encode('utf-8'))
respone=tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close() if __name__ == '__main__':
ip_port=('127.0.0.1',9999)
bufsize=1024
client_handler(ip_port,bufsize)

  

python网络编程基础之socket粘包现象的更多相关文章

  1. Python网络编程(2)-粘包现象及socketserver模块实现TCP并发

    1. 基于Tcp的远程调用命令实现 很多人应该都使用过Xshell工具,这是一个远程连接工具,通过上面的知识,就可以模拟出Xshell远程连接服务器并调用命令的功能. Tcp服务端代码如下: impo ...

  2. Java网络编程基础之TCP粘包拆包

    TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想象河里的流水,他们是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,他会根据TCP缓冲区的实 ...

  3. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  4. Python网络编程基础pdf

    Python网络编程基础(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1VGwGtMSZbE0bSZe-MBl6qA 提取码:mert 复制这段内容后打开百度网盘手 ...

  5. 好书推荐---Python网络编程基础

    Python网络编程基础详细的介绍了网络编程的相关知识,结合python,看起来觉得很顺畅!!!

  6. Python网络编程基础|百度网盘免费下载|零基础入门学习资料

    百度网盘免费下载:Python网络编程基础|零基础学习资料 提取码:k7a1 目录: 第1部分 底层网络 第1章 客户/服务器网络介绍 第2章 网络客户端 第3章 网络服务器 第4章 域名系统 第5章 ...

  7. socket粘包现象加解决办法

    socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...

  8. 从零开始学Python第八周:网络编程基础(socket)

    Socket网络编程 一,Socket编程 (1)Socket方法介绍 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Soc ...

  9. python网络编程基础

    一.客户端/服务器架构 网络中到处都应有了C/S架构,我们学习socket就是为了完成C/S架构的开发. 二.scoket与网络协议 如果想要实现网络通信我们需要对tcpip,http等很多网络知识有 ...

随机推荐

  1. Linux下解析域名命令-dig 命令使用详解

    Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息.dig 命令主要用来从 DNS 域名服务器查询主机地址信息.dig的全称是 (dom ...

  2. Kattis之旅——Rational Arithmetic

    Input The first line of input contains one integer, giving the number of operations to perform. Then ...

  3. Java 安全套接字编程以及keytool 使用最佳实践

    概述 利用 Java 的 JSSE(Java Secure Socket Extension)技术,我们可以方便的编写安全套接字程序,关于 JSSE 的介绍,可以参阅 Oracle 网站提供的 JSS ...

  4. mysqldump进行复制数据导出导入时的问题

    在执行数据导入到从库时,若使用mysqldump命令进行数据导出,应当一次性将需要同步的库导出. mysqldump -uroot -p --single-transaction --database ...

  5. dubbo spring pom文件报错:提示no declaration can be found for element 'dubbo:service'.

    pom文件报错:The matching wildcard is strict, but no declaration can be found for  element 'dubbo:service ...

  6. intel webrtc 部署

    org link conference server Configure the MCU server 1. set the maximum numbers of open files, runnin ...

  7. Idea 破解教程 (2018.11-29最新版)

    一.下载安装idea,这里不做赘述.官网-https://www.jetbrains.com/idea/ 二.安装完idea后,需要激活使用.这里需要先下载个工具包 ,下载网址http://idea. ...

  8. windows模糊查询指定进程是否存在

    习惯的查询 wmic process | findStr /i "**" /i 忽略大小写 我查考的链接 常用批处理命令总结3之Find和FindStr

  9. Microsoft Visual Studio 2010(vs10)安装与使用

    安装1.下载软件: 云盘分享http://pan.baidu.com/s/1i4JL9GT 2.安装 打开Microsoft Visual Studio 2010目录,双击setup.exe ,运行 ...

  10. 【python016--序列】

    一.列表,元组和字符串的共同点 --都可以通过索引得到每一个元素 --默认索引值总是从0开始 --可以通过分片的方法得到一个范围内的元素的集合 --有很多共同的操作符(重复操作符,拼接操作符.成员关系 ...