首页 > 编程语言 > 详细

Python基础之-socket编程

时间:2018-06-18 16:32:32      阅读:216      评论:0      收藏:0      [点我收藏+]

粘包现象

让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig)

注意注意注意:

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

的结果的编码是以当前所在的系统为准的,如果是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端需要用GBK解码

且只能从管道里读一次结果

注意:命令ls -l ; lllllll ; pwd 的结果是既有正确stdout结果,又有错误stderr结果

技术分享图片
#!/usr/bin/python3
#_*_coding:utf-8_*_
#__author__ = ‘Tengbibo‘

import socket
import subprocess

ip_port = (127.0.0.1,6969)
BUFSIZE = 1024

tcp_socket_server = socket.socket()
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)

while True:
    conn,addr = tcp_socket_server.accept()
    print(connect from:,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 = res.stderr.read()
        stdout = res.stdout.read()
        conn.send(stderr)
        conn.send(stdout)
服务端
技术分享图片
#!/usr/bin/python3
#_*_coding:utf-8_*_
#__author__ = ‘Tengbibo‘

import socket
BUFSIZE=1024
ip_port=(127.0.0.1,6969)

client = socket.socket()
client.connect(ip_port)

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

    client.send(cmd.encode(utf-8))
    act_res=client.recv(BUFSIZE)

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

上述程序是基于tcp的socket,在运行时会发生粘包

 

什么是粘包

须知:只有TCP有粘包现象,UDP永远不会粘包。

首先需要掌握一个socket收发消息的原理

                  技术分享图片

 

发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的。怎样定义消息呢?可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束

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

此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

  1. TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
  2. UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。
  3. tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头,实验略

udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y>x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠

tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

 

Python基础之-socket编程

原文:https://www.cnblogs.com/cyfiy/p/9195414.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!