TCP和UDP协议,socket套接字,半连接池,粘包问题的处理措施

一:TCP和UDP协议

1.tcp协议

1.三次握手

  • 1>客户端向服务端发送请求,想要建立一条客户端到服务端的传输数据通道
  • 2>服务端向客户端发送回复,同意连接请求,并且同时发送了想要建立从服务端到客户端传输数据通道的请求
  • 3>客户端向服务端发送回复,同意连接请求

2.四次挥手

  • 1>客户端向服务端发送请求,想要断开客户端到服务端的数据传输的通道
  • 2>服务端向客户端发送回复,同意断开请求
  • 3>服务端向客户端发送请求,想要断开服务端到客户端的数据传输通道
  • 4>客户端向服务端发送回复,同意断开请求

二:socket套接字

1.最基本的服务端:
import socket

server = socket.socket()

server.bind(('127.0.0.1', 8090))

server.listen(5)


sock, addr = server.accept()

sock.send(b'I am server')

data = sock.recv(1024)
print(data)

sock.close()
server.close()
2.最基本的客户端
import socket

client = socket.socket()

client.connect(('127.0.0.1', 8090))

data = client.recv(1024)

print(data)
client.send(b'I am client ')

client.close()
3.能够简单实现循环功能的服务端
import socket

server = socket.socket()

server.bind(('127.0.0.1', 8090))

server.listen(5)

while True:
    sock, addr = server.accept()
    while True:
        msg = input('请输入你想要说的话').strip()
        sock.send(msg.encode('utf8'))
        data = sock.recv(1024)
        print(data.decode('utf8'))
4.能够简单实现循环功能的客户端
import socket

client = socket.socket()

client.connect(('127.0.0.1', 8090))

while True:
    data = client.recv(1024)
    print(data.decode('utf8'))
    msg = input('请输入你想说的话').strip()
    client.send(msg.encode('utf8'))

三:半连接池

server.listen(5)
1.语言描述什么是半连接池?
  • 所谓的半连接池就相当于是等待服务的固定名额,当名额空出来后,便可以立即添加新的进去等待服务

四:粘包问题

1.出现粘包问题的原因?
  • 1.TCP特性
    流式协议:所有的数据类似于水流 连接在一起的
    例如:当数据量很小 并且时间间隔很多 那么就会自动组织到一起,出现粘包问题
  • 2.recv接收出造成的
    我们不知道即将要接收的数据量多大 如果知道的话不会产生也不会产生黏包
2.解决粘包问题的方法
  • 1.方法:用struct模块无论数据长度是多少 都可以帮你打包成固定长度 然后基于该固定长度 还可以反向解析出真实长度

  • 2.思路:

    • 服务端
      1.先将真实数据的长度制作成固定长度 4
      2.先发送固定长度的报头
      3.再发送真实数据

    • 客户端

      ​ 1.先接收固定长度的报头 4
      ​ 2.再根据报头解压出真实长度
      ​ 3.根据真实长度接收即可

  • 3.实际案例

  • 服务端

import socket
import os
import struct
import json

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

while True:
    sock, address = server.accept()
    while True:
        file_dict = {
            'file_name': '葫芦娃.txt',
            'file_size': os.path.getsize(r'../葫芦娃.txt'),
            'file_desc': '大战蛇妖',
        }
        # 2.将字典打包成固定长度的数据
        dict_json = json.dumps(file_dict)
        file_bytes_dict = dict_json.encode('utf8')
        dict_len = struct.pack('i', len(file_bytes_dict))
        # 3.发送固定长度的字典报头
        sock.send(dict_len)
        # 4.发送真实字典数据
        sock.send(dict_json.encode('utf8'))
        # 5.发送真实数据
        with open(r'../葫芦娃.txt', 'rb') as f:
            for line in f:
                sock.send(line)
        break

  • 客户端
import socket
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1', 8888))

while True:
    # 1.先接收长度为4的报头数据
    header_len = client.recv(4)
    # 2.根据报头解包出字典的长度
    dict_len = struct.unpack('i', header_len)[0]
    # 3.直接接收字典数据
    dict_data = client.recv(dict_len)
    # 4.解码并反序列化出字典
    real_dict = json.loads(dict_data)
    print(real_dict)
    # 5.从数据字典中获取真实数据的各项信息
    total_size = real_dict.get('file_size')
    file_size = 0
    with open(r'%s' % real_dict.get('file_name'), 'wb') as f:
        while file_size < total_size:
            data = client.recv(1024)
            f.write(data)
            file_size += len(data)
        print('文件接收完毕')
        break

你可能感兴趣的:(python零基础,网络编程,tcp/ip,udp,网络)