网络编程 之粘包问题、使用socketserver实现并发

一、粘包问题

注意:粘包问题只有tcp协议并且udp协议永远不会粘包

粘包问题的产生:

简述:粘包问题的产生主要是由于tcp协议传输数据(其内置的nagle算法来进行的)会将数据较小的且发送时间较短的合并成一个包从发送端发送出去,接收端不知道该怎么去想要的数据拿出来这样造成了粘包问题,另一方面是由于时间太短接收端没有及时拿干净

传来的数据造成数据混乱(这是因为tcp协议又叫流氏协议指的是其就像水流一样传输数据)才产生的粘包问题。

1、发送端由于时间太短造成多个包合在一起发送产生粘包问题的实例如下:

服务端:

from socket import *
ip_port=(‘127.0.0.1‘,8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)

conn,addr=tcp_socket_server.accept()

data1=conn.recv(10)
data2=conn.recv(10)

print(‘----->‘,data1.decode(‘utf-8‘))
print(‘----->‘,data2.decode(‘utf-8‘))

conn.close()

客户端:

import socket
BUFSIZE=1024
ip_port=(‘127.0.0.1‘,8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)

s.send(‘hello‘.encode(‘utf-8‘))
s.send(‘feng‘.encode(‘utf-8‘))

2、由于接收端没有接收干净发送端发来的数据造成的粘包问题的实例如下:

服务端:

from socket import *
ip_port=(‘127.0.0.1‘,8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)

conn,addr=tcp_socket_server.accept()

data1=conn.recv(2) #一次没有收完整
data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

print(‘----->‘,data1.decode(‘utf-8‘))
print(‘----->‘,data2.decode(‘utf-8‘))

conn.close()

客户端:

import socket
BUFSIZE=1024
ip_port=(‘127.0.0.1‘,8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)

s.send(‘hello feng‘.encode(‘utf-8‘))

3、粘包现象出现的实例如下:
3.1基于subprocess模块产生的粘包现象

服务端:

from socket import *
import subprocess

ip_port=(‘127.0.0.1‘,8080)
BUFSIZE=1024

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)

while True:
    conn,addr=tcp_socket_server.accept()
    print(‘客户端‘,addr)

    while True:
        cmd=conn.recv(BUFSIZE)
        if len(cmd) == 0:break

        res=subprocess.Popen(cmd.decode(‘utf-8‘),shell=True,
                         stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE,
                         stderr=subprocess.PIPE)

        stderr=act_res.stderr.read()
        stdout=act_res.stdout.read()
        conn.send(stderr)
        conn.send(stdout)

客户端:

import socket
BUFSIZE=1024
ip_port=(‘127.0.0.1‘,8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)

while True:
    msg=input(‘>>: ‘).strip()
    if len(msg) == 0:continue
    if msg == ‘quit‘:break

    s.send(msg.encode(‘utf-8‘))
    act_res=s.recv(BUFSIZE)

    print(act_res.decode(‘utf-8‘),end=‘‘)

3.2使用struct模块的解决方案
服务端:

import socket,json,struct,subprocess
ip_port=(‘127.0.0.1‘,2206)
ip_base=1024
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ip_port)
server.listen(5)
while True:
    conn,adder=server.accept()
    while True:
        try:
            data=conn.recv(ip_base)
            if len(data)==0:
                break
            res=subprocess.Popen(data.decode(‘utf-8‘),shell=True,stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdout=res.stdout.read()
            stderr=res.stderr.read()
            head_dic={‘filname‘:‘dir‘,‘md5‘:‘fffff‘,‘head‘:len(stdout)+len(stderr)}
            head_json=json.dumps(head_dic)
            head_bytes=head_json.encode(‘utf-8‘)
            conn.send(struct.pack(‘i‘,len(head_bytes)))
            conn.send(head_bytes)
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
    conn.close()
server.colse()

客户端:

import socket,json,struct
ip_port=(‘127.0.0.1‘,2206)
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(ip_port)
while True:
    mag=input(‘>>>:‘).strip()
    if len(mag)==0:
        continue
    client.send(mag.encode(‘utf-8‘))
    #先拿到报头的固定长度(4bytes)
    head_len=struct.unpack(‘i‘,client.recv(4))[0]
    #再拿到报头
    head_bytes=client.recv(head_len)
    head_json=head_bytes.decode(‘utf-8‘)
    head_dic=json.loads(head_json)
    #拿到报头的中数据的长度
    total=head_dic[‘head‘]
    rb=b‘‘
    stawith=0
    while stawith<total:
        data=client.recv(total)
        stawith+=len(data)
        rb+=data
    print(rb.decode(‘gbk‘))
client.close()

补充:为何udp协议不会发生粘包问题是由于udp协议不是通过连接进行数据传输的并且基于udp协议发送的数据都会自带报头,
所以接收端可以通过每条数据的报头去取出数据并且udp协议传输数据是传一个数据就立马删除掉这样不会让接收端由于接受不

急时而造成数据混乱。(udp协议也可以叫数据报协议)

二、使用socketserver模块实现并发

1、基于tcp协议通信实现并发

服务端:

import socketserver
class Myudpheadler(socketserver.DatagramRequestHandler):
    def handle(self):
        while True:
            data,sock=self.request()
            sock.sendto(data,self.client_address)
if __name__ == ‘__main__‘:
    sever=socketserver.ThreadingUDPServer((‘127.0.0.1‘,2221),Myudpheadler)
    sever.serve_forever()

客户端:

from socket import *
ip_port=(‘127.0.0.1‘,2221)
client=socket(AF_INET,SOCK_DGRAM)
while True:
    mad=input(‘>>>>:‘).strip()
    if len(mad)==0:
        continue
    client.sendto(mad.encode(‘utf-8‘),ip_port)
    adder,sock=client.recvfrom(1024)
    print(adder)
    print(sock)
client.close()

2、基于udp协议通信实现并发
服务端:

import socketserver
class mudphead(socketserver.DatagramRequestHandler):
    def handle(self):
        while True:
            data,sock=self.request()
            sock.sendto(data,self.client_address)
if __name__ == ‘__main__‘:
    server=socketserver.ThreadingUDPServer((‘127.0.0.1‘,2220),mudphead)
    server.serve_forever()

客户端:

from socket import *
ip_port=(‘127.0.0.1‘,2206)
client=socket(AF_INET,SOCK_DGRAM)
while True:
    client.sendto(‘hello‘.encode(‘utf-8‘),ip_port)
    adder,scok=client.recvfrom(1024)
    print(adder)
client.close()

补充:基于udp协议其自身就可以实现通信实现并发。

原文地址:https://www.cnblogs.com/ageliu/p/9651951.html

时间: 2024-08-29 20:47:50

网络编程 之粘包问题、使用socketserver实现并发的相关文章

网络编程中粘包的处理方法

写在前面的话:因为自己是才解除网络编程,在工作中第一次遇到粘包问题,我还不知道它是叫粘包问题,所以被整的晕头转向,百思不得其解,自己的代码到底哪里出了问题,最后只能单步调试程序才发现接收方接收到的数据并不一定是按自己设想那样,一次接收整个数据包,当时就想到用文件长度来判断是否接收完文件,之后读了UNP才知道是粘包问题.记录以下当时自己的处理方法. 面对网络编程中的发送文件时的粘包问题,我的处理方法是在要发送文件前,首先发送文件的长度,获取的文件长度是UlongLong类型的整数,发送 时需要转换

网络编程基础粘包现象

粘包 tcp是流式传输,字节流,数据与数据之间是没有边界的 流式传输优点: 不限定长度 可靠传输 缺点: 慢 和一个人的通信连接conn会一直占用我们的通信资源 udp协议,面向数据包的传输 数据包优点 快 由于不需要建立连接,所以谁发的消息我都能接受到 缺点 不能传输过长的数据 不可靠 粘包现象 由于流式传输的特点,产生了数据连续发送的粘包现象. 在一个conn建立起来的连接上传输的多条数据是没有边界的 数据的发送和接收实际上不是在执行send/recv的时候就立刻被发送和接收,而是需要经过操

Learning-Python【29】:网络编程之粘包

粘包问题 上一篇博客遗留了一个问题,在接收的最大字节数设置为 1024 时,当接收的结果大于1024,再执行下一条命令时还是会返回上一条命令未执行完成的结果.这就是粘包问题. 因为TCP协议又叫流式协议,每次发送给客户端的数据实际上是发送到客户端所在操作系统的缓存上,客户端就是一个应用程序,需要通过操作系统才能调到缓存内的数据,而缓存的空间是一个队列,有 “先进先出” 的思想,当第一次的 tasklist 数据未接收完,第二次又来一个 dir 的数据时,只能等第一次先全部接收完成才会接收后面的.

网络编程-之------粘包现象

一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原理 应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因.(因为TCP是流式协议,不知道啥时候开始,啥时候结束).而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提

网络编程ssh,粘包

1.什么是socket? TCP,可靠地,面向连接协议,有阻塞rect udp,不可靠的,无线连接的服务 这里因为不需要阻塞,所以速度会很快,但安全性不高 2.关于客户端退出而服务器未退出的解决办法 1 import socket 2 sock=socket.socket() # TCP协议 3 IP_PORT=("127.0.0.1",8899) 4 sock.bind(IP_PORT) 5 sock.listen(5) 6 while 1: 7 conn,addr=sock.acc

网络编程之粘包

粘包: 传输层协议有tcp和udp两种 tcp:Transmission Control Protocol 传输控制协议,基于数据流,收发的消息不能为空,需要在客户端和服务端都添加空消息的处理机制 tcp是可靠性协议,数据的收发都需要确认信息,这就降低了传输效率,故为了减少确认次数,tcp采用了nagle算法 将多次间隔短且数据小的数据合成一个数据流,然后发送,tcp的数据没有明确的界限,无法区分数据的开始和结束, 这就导致了可能将多个信息并为一条信息,也就是粘包 还有一种粘包情况是当一个数据包

解决网络编程的粘包问题

# 服务端 import socketimport subprocessimport structimport json servers = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)servers.bind(('127.0.0.1', 7777))servers.listen(10)print('start settings') while True:    """连接循环""

python/socket编程之粘包

python/socket编程之粘包 粘包: 只有TCP有尿包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提取数据,当然也有可能是3k或者多k提取数据,也就是说,应用程序是不可见的,因此TCP协议是面来那个流的协议,这也是容易出现粘包的原因而UDP是面向笑死的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任一字节的数据,这一点和TCP是很同的.怎样定义消息呢?认为对方一次

python网络编程基础(线程与进程、并行与并发、同步与异步)

python网络编程基础(线程与进程.并行与并发.同步与异步) 目录 线程与进程 并行与并发 同步与异步 线程与进程 进程 前言 进程的出现是为了更好的利用CPU资源使到并发成为可能. 假设有两个任务A和B,当A遇到IO操作,CPU默默的等待任务A读取完操作再去执行任务B,这样无疑是对CPU资源的极大的浪费.聪明的老大们就在想若在任务A读取数据时,让任务B执行,当任务A读取完数据后,再切换到任务A执行.注意关键字切换,自然是切换,那么这就涉及到了状态的保存,状态的恢复,加上任务A与任务B所需要的