TCP大文件上传与UDP协议

一、UCP大文件上传(解决粘包问题)

①客户端

import socket, os, json, struct

client = socket.socket()
client.connect(('127.0.0.1', 8080))
# 文件大小
file_size = os.path.getsize(r'D:Desktopwendang.txt')

# 文件名
file_name = '计算机五大.txt'

# 然后定义一个字典
d = {
    'file_name': file_name,
    'file_size': file_size,
    'msg': '成功上传'
}
# 定义好字典后,先去转一下json,然后encode
data_bytes = json.dumps(d).encode('utf-8')

# 制作字典的报头
header = struct.pack('i', len(data_bytes))

# 发送报头
client.send(header)

# 发送字典
client.send(data_bytes)

# 然后发送真实数据:打开文件,一行一行读取出来,一行一行的发送
with open(r'D:Desktopwendang.txt', 'rb') as f:
    for line in f:
        client.send(line)

②服务端

import socket, json, struct

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

while True:
    conn, addr = server.accept()
    while True:
        try:
            # 先接收报头
            header = conn.recv(4)

            # 解析报头,获取字典长度
            header_len = struct.unpack('i', header)[0]

            # 接收字典
            header_bytes = conn.recv(header_len)
            header_dic = json.loads(header_bytes.decode('utf_8'))
            print(header_dic)    # 打印字典

            # 循环接收文件,存储到本地
            file_size = header_dic.get('file_size')
            file_name = header_dic.get('file_name')
            recv_size = 0

            # 文件操作
            with open(file_name, 'wb') as f:
                while recv_size < file_size:    # 循环接收
                    data = conn.recv(1024)
                    f.write(data)
                    recv_size += len(data)
            print(header_dic.get('msg'))   # 文件上传成功后的提示信息
          
        except ConnectionResetError:
            break
    conn.close()

二、UDP协议(数据报协议):

没有双向通道,传输数据不可靠,可能出现丢包现象

通信速度比较快,发送的数据不会在内存中保留

1、特性:

①UDP协议不存在粘包问题

②客户端可以发空,自带数据报头

③udp可以实现并发的效果

④服务端不存在,也不影响客户端朝服务端发送数据

2、分析:

①UDP叫数据报协议,意味着发消息都带有数据报头

②UDP的server不需要就行监听也不需要建立连接

③启动服务之后只能被动的等待客户端发消息过来,

  客户端发消息的时候,带上服务端的地址 client.sendto(b'hello', server_addr)

  服务端发消息的时候,带上客户端的地址 server.sendto(msg.upper(), addr)

3、TCP和UDP

TCP:类似于打电话,要确定服务端收到

UDP:类似于发短信,不考虑服务端是否收到

4、UDP简单使用

①服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

msg, addr = server.recvfrom(1024)
server.sendto(msg.upper(), addr)
print(msg, addr)

②客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)  # 服务端地址,通常写在配置文件中

client.sendto(b'hello', server_addr)

msg, addr = client.recvfrom(1024)
print(msg, addr)

5、UDP不存在粘包现象

UDP不存在粘包现象,是由于UDP发送的时候,没有经过Negal算法优化,不会将多个小包合并一次发送出去。另外,在UDP协议的接收端,采用了链式结构来记录每一个到达的UDP包,这样接收端应用程序一次recv只能从socket接收缓冲区中读出一个数据包。也就是说,发送端send了几次,接收端必须recv几次(无论recv时指定了多大的缓冲区)。

①服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

# 验证udp是否粘包:不粘包
msg, addr = server.recvfrom(1024)
print(msg)    # b'baby~'
msg1, addr1 = server.recvfrom(1024)
print(msg1)   # b'baby~'
msg2, addr2 = server.recvfrom(1024)
print(msg2)   # b'baby~'

②客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)  # 服务端地址,通常写在配置文件中


# 验证udp是否粘包:不粘包
client.sendto(b'baby~', server_addr)
client.sendto(b'baby~', server_addr)
client.sendto(b'baby~', server_addr)

三、基于UDP实现简易版本的QQ

 ①服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))

while True:
    msg,addr = server.recvfrom(1024)
    print(msg.decode('utf-8'))
    data = input('>>>:').encode('utf-8')
    server.sendto(data,addr)

②客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1',8080)

while True:
    msg = input('>>>:')
    msg = '客户端1的消息:%s'%msg
    client.sendto(msg.encode('utf-8'),server_addr)
    data,addr = client.recvfrom(1024)
    print(data)

四、socketserver模块

 1、能够实现并发效果
   并发:看起来像同时运行就能称之位并发
 2、udp在使用的时候,多个客户端要有一些io操作,不然容易卡死

原文地址:https://www.cnblogs.com/zhangguosheng1121/p/10822698.html