tcp协议之recv

Posted walle-zhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tcp协议之recv相关的知识,希望对你有一定的参考价值。

写一个下载功能的时候遇到的一个bug。

技术图片
import socket
import struct
import json
import os
base_dir = os.getcwd()
print(base_dir)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8889))
while True:
    msg = input(">>:")
    if not msg:
        continue
    client.send(msg.encode("utf-8"))
    heard_data = client.recv(4)
    heard_len = struct.unpack("i", heard_data)[0]

    heard_bytes = client.recv(heard_len)
    heard = json.loads(heard_bytes.decode("utf-8"))
    filename = heard["filename"]
    md5 = heard["md5"]
    filesize = heard["filesize"]
    data = b""
    recv_size = 0
    while filesize > 0:  # 判断条件为什么不能使用while filesize > 0:
        msg = client.recv(1024)
        print(len(msg))
        data += msg
        filesize -= 1024   # 这里的一个问题,为什么不能使用filesize -= 1024
    with open("{}/test/downloads/{}".format(base_dir, filename), "wb") as f:
        f.write(data)
    print("下载成功")
client.close()
client
技术图片
import socket
import os
import struct
import json
base_dir = os.getcwd()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8889))
server.listen(5)
while True:
    client,address = server.accept()
    while True:
        try:
            cmd_recv = client.recv(1024)
            if not cmd_recv:
                break
            cmd = cmd_recv.decode("utf-8")
            filename = cmd.split()[1]
            filesize = os.path.getsize("{}/test/share/{}".format(base_dir, filename))
            print(filesize)
            heard = {
                "filename": filename,
                "filesize": filesize,
                "md5": "xxxx",
            }
            heard_str = json.dumps(heard)
            heard_len = struct.pack("i", len(heard_str))
            client.send(heard_len)
            client.send(heard_str.encode("utf-8"))
            with open("{}/test/share/{}".format(base_dir, filename), "rb") as f:
                for line in f:
                    client.send(line)
        except Exception as e:
            print(e)
            break
    client.close()
server.close()
server

这里是客户端的问题,就是在recv的时候,每次接收1024个,但是实际上可能发送的并没有1024个,这个时候recv并不会一直等待着,而在一定的时间之后能接受多少先接收多少。

所以,这里在print(len(msg))的时候,就会发现中间有一些是没有达到1024个字符。

技术图片

因此下面filesize -= 1024就是错误的。改正过来的客户端代码如下:

技术图片
import socket
import struct
import json
import os
base_dir = os.getcwd()
print(base_dir)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8889))
while True:
    msg = input(">>:")
    if not msg:
        continue
    client.send(msg.encode("utf-8"))
    heard_data = client.recv(4)
    heard_len = struct.unpack("i", heard_data)[0]

    heard_bytes = client.recv(heard_len)
    heard = json.loads(heard_bytes.decode("utf-8"))
    filename = heard["filename"]
    md5 = heard["md5"]
    filesize = heard["filesize"]
    data = b""
    recv_size = 0
    while filesize > 0:  # 判断条件为什么不能使用while filesize > 0:
        msg = client.recv(1024)
        data += msg
        filesize -= len(msg)  # 这里的一个问题,为什么不能使用filesize -= 1024
    with open("{}/test/downloads/{}".format(base_dir, filename), "wb") as f:
        f.write(data)
    print("下载成功")
client.close()
改正客户端

 

以上是关于tcp协议之recv的主要内容,如果未能解决你的问题,请参考以下文章

深入理解TCP协议及其源代码——send和recv背后数据的收发过程

TCP/IP应用层协议实现 - 数据收发send/recv(lwip)

TCP/IP应用层协议实现 - 数据收发send/recv(lwip)

TCP 之 TCP_NEW_SYN_RECV状态

Socket之send和recv原理剖析&TCP网络应用程序的注意点

深入理解TCP协议及其源代码