""" 
  什么是粘包:
    上一次传输的数据 没有被完全接收掉
    保存在了缓存区 下一次再往该地方发数据
    就会跟着一起发送过去了，导致数据全部乱了
  为什么会粘包:
    1、因为TCP是基于流传输数据的 流式协议  数据像水一样流过去  数据与数据之间没有边界
    使用了优化方法（Nagle算法），将多次间隔较小且数据量小的数据，合并成一个大的数据块，然后进行封包。

    2、TCP协议的接收方和传输方 都有一个缓存机制
    所有数据都先经过缓存区 然后再根据设置的大小提取数据

    所以导致如果同一次连接发送的数据 没有被完全接收 就会遗留在缓冲区中 并跟随下一次继续传输

  为什么不能完全接收数据:
    前置知识点: 应用程序的数据是从内存读取的  内存的数据又是从硬盘或者网络中传输过来的
    1、不知道此次传输的数据的大小，如果比设定的允许接收数据的值小 则没问题 如果比设定值大 则遗留在缓存区了
    2、即使接收值够大，用完内存剩余空间 但传输的数据已经比内存还大，那么多余数据必然无法保存到内存当中 也只能遗留在缓存区
  
  解决方案:
    根据上述原因，可得出主要问题就是 不知道数据大小 数据过大又无法保存
    1、数据大小:
      自定义协议，先发送一个请求头(固定字节) 告诉客户端 我传输的数据有多大 请你做好准备
      工具:struct模块
    2、数据过大:
      添加一个累加器，累加每次接受到的数据  当累加器的值等于数据大小 停止循环接受数据


    阻塞模式
      对于TCP套接字（默认情况下），当使用 write()/send() 发送数据时：
        1) 首先会检查缓冲区，如果缓冲区的可用空间长度小于要发送的数据，那么 write()/send() 会被阻塞（暂停执行），直到缓冲区中的数据被发送到目标机器，腾出足够的空间，才唤醒 write()/send() 函数继续写入数据。
        2) 如果TCP协议正在向网络发送数据，那么输出缓冲区会被锁定，不允许写入，write()/send() 也会被阻塞，直到数据发送完毕缓冲区解锁，write()/send() 才会被唤醒。
        3) 如果要写入的数据大于缓冲区的最大长度，那么将分批写入。
        4) 直到所有数据被写入缓冲区 write()/send() 才能返回。
      当使用 read()/recv() 读取数据时：
        1) 首先会检查缓冲区，如果缓冲区中有数据，那么就读取，否则函数会被阻塞，直到网络上有数据到来。
        2) 如果要读取的数据长度小于缓冲区中的数据长度，那么就不能一次性将缓冲区中的所有数据读出，剩余数据将不断积压，直到有 read()/recv() 函数再次读取。
        3) 直到读取到数据后 read()/recv() 函数才会返回，否则就一直被阻塞。
        这就是TCP套接字的阻塞模式。所谓阻塞，就是上一步动作没有完成，下一步动作将暂停，直到上一步动作完成后才能继续，以保持同步性。

"""

import socket
import struct

HOST = '127.0.0.1'
PORT = 8080
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen()
while True:
  c,addr = s.accept()

  with open('readme','r',encoding='utf-8') as f:
    # struct.pack 把一个数字 打包成固定长度的字节  接收端通过unpack 解包 得知此次传输数据的字节(大小)
    header = struct.pack('i',len(f.read()))
    c.send(header)
    f.seek(0) # 注意指针
    for line in f:
       c.send(str(line).encode())
    c.close()


s.close()

8979ba333329c3b28996365ce6649235501613cc
<mask token>

<mask token>
s.bind((HOST, PORT))
s.listen()
while True:
    c, addr = s.accept()
    with open('readme', 'r', encoding='utf-8') as f:
        header = struct.pack('i', len(f.read()))
        c.send(header)
        f.seek(0)
        for line in f:
            c.send(str(line).encode())
        c.close()
s.close()

<mask token>
HOST = '127.0.0.1'
PORT = 8080
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
while True:
    c, addr = s.accept()
    with open('readme', 'r', encoding='utf-8') as f:
        header = struct.pack('i', len(f.read()))
        c.send(header)
        f.seek(0)
        for line in f:
            c.send(str(line).encode())
        c.close()
s.close()

<mask token>
import socket
import struct
HOST = '127.0.0.1'
PORT = 8080
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
while True:
    c, addr = s.accept()
    with open('readme', 'r', encoding='utf-8') as f:
        header = struct.pack('i', len(f.read()))
        c.send(header)
        f.seek(0)
        for line in f:
            c.send(str(line).encode())
        c.close()
s.close()

""" 
  什么是粘包:
    上一次传输的数据 没有被完全接收掉
    保存在了缓存区 下一次再往该地方发数据
    就会跟着一起发送过去了，导致数据全部乱了
  为什么会粘包:
    1、因为TCP是基于流传输数据的 流式协议  数据像水一样流过去  数据与数据之间没有边界
    使用了优化方法（Nagle算法），将多次间隔较小且数据量小的数据，合并成一个大的数据块，然后进行封包。

    2、TCP协议的接收方和传输方 都有一个缓存机制
    所有数据都先经过缓存区 然后再根据设置的大小提取数据

    所以导致如果同一次连接发送的数据 没有被完全接收 就会遗留在缓冲区中 并跟随下一次继续传输

  为什么不能完全接收数据:
    前置知识点: 应用程序的数据是从内存读取的  内存的数据又是从硬盘或者网络中传输过来的
    1、不知道此次传输的数据的大小，如果比设定的允许接收数据的值小 则没问题 如果比设定值大 则遗留在缓存区了
    2、即使接收值够大，用完内存剩余空间 但传输的数据已经比内存还大，那么多余数据必然无法保存到内存当中 也只能遗留在缓存区
  
  解决方案:
    根据上述原因，可得出主要问题就是 不知道数据大小 数据过大又无法保存
    1、数据大小:
      自定义协议，先发送一个请求头(固定字节) 告诉客户端 我传输的数据有多大 请你做好准备
      工具:struct模块
    2、数据过大:
      添加一个累加器，累加每次接受到的数据  当累加器的值等于数据大小 停止循环接受数据


    阻塞模式
      对于TCP套接字（默认情况下），当使用 write()/send() 发送数据时：
        1) 首先会检查缓冲区，如果缓冲区的可用空间长度小于要发送的数据，那么 write()/send() 会被阻塞（暂停执行），直到缓冲区中的数据被发送到目标机器，腾出足够的空间，才唤醒 write()/send() 函数继续写入数据。
        2) 如果TCP协议正在向网络发送数据，那么输出缓冲区会被锁定，不允许写入，write()/send() 也会被阻塞，直到数据发送完毕缓冲区解锁，write()/send() 才会被唤醒。
        3) 如果要写入的数据大于缓冲区的最大长度，那么将分批写入。
        4) 直到所有数据被写入缓冲区 write()/send() 才能返回。
      当使用 read()/recv() 读取数据时：
        1) 首先会检查缓冲区，如果缓冲区中有数据，那么就读取，否则函数会被阻塞，直到网络上有数据到来。
        2) 如果要读取的数据长度小于缓冲区中的数据长度，那么就不能一次性将缓冲区中的所有数据读出，剩余数据将不断积压，直到有 read()/recv() 函数再次读取。
        3) 直到读取到数据后 read()/recv() 函数才会返回，否则就一直被阻塞。
        这就是TCP套接字的阻塞模式。所谓阻塞，就是上一步动作没有完成，下一步动作将暂停，直到上一步动作完成后才能继续，以保持同步性。

"""

import socket
import struct

HOST = '127.0.0.1'
PORT = 8080
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen()
while True:
  c,addr = s.accept()

  with open('readme','r',encoding='utf-8') as f:
    # struct.pack 把一个数字 打包成固定长度的字节  接收端通过unpack 解包 得知此次传输数据的字节(大小)
    header = struct.pack('i',len(f.read()))
    c.send(header)
    f.seek(0) # 注意指针
    for line in f:
       c.send(str(line).encode())
    c.close()


s.close()
