socket与struct模块

一、socket模块

    socket简介

      Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    socket简易代码 (以C/S架构为例)

      服务端

import socket

server = socket.socket()

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

server.listen(5)
sock, addr = server.accept()
print(addr)
data = sock.recv(1024)
print(data)
sock.send(b'hahaha')
sock.close()
server.close()

      客户端

import socket

client = socket.socket()
client.connect(('127.0.0.1', 8090))
client.send(b'xixixi')
data = client.recv(1024)
print(data)
client.close()

    优化版本     

      1.客户端校验消息不能为空
      2.服务端添加兼容性代码(mac linux)

        在服务端添加 if recv ==0 :continue
      3.服务端重启频繁报端口占用错误
        from socket import SOL_SOCKET, SO_REUSEADDR
        server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 在bind前加
      4.客户端异常关闭服务端报错的问题
        使用异常捕获

      服务端

import socket
import struct
import json

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
    sock, addr = server.accept()
    while True:
    data = sock.recv(1024)
    print(data)
    sock.send(b'hahaha')
    sock.close()
    server.close()

      客户端

import socket

client = socket.socket()
client.connect(('127.0.0.1', 8090))
client.send(b'xixixi')
data = client.recv(1024)
print(data)
client.close()

  

 

二、struct模块

      struct模块可以解决文件传输时的黏包现象

    什么是黏包?

        在数据传输时,数据没有完全传输完,还留在管道内。

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

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

    解决黏包情况(以上面的数据传输代码为例)

      服务端

import socket
import struct
import json

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
    sock, addr = server.accept()
    while True:
        head_data = sock.recv(4)
        # 解析报头
        dict_length = struct.unpack('i', head_data)[0]
        # 接收字典
        dict_data = sock.recv(dict_length)
        # 反序列化字典并解码
        dict_real = json.loads(dict_data)
        # 取出字典的中的文件大小
        file_size = dict_real.get('size')
        file_name = dict_real.get('filename')
        # 上传文件
        recv_size = 0
        with open('filename', 'wb') as f:
            while recv_size < file_size:
                data = sock.recv(1024)
                recv_size += len(data)
                f.write(data)

      客户端

import os
import socket
import json
import struct



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

while True:
    data_path = r'D:\BaiduNetdiskDownload\视频'
    movie_list = os.listdir(data_path)
    for i, j in enumerate(movie_list, 1):
        print(i, j)
    choice = input('请输入编号>>>: ')
    if choice == 0:
        continue
    if choice.isdigit():
        choice = int(choice)
        if choice in range(1, len(movie_list) + 1):
            movie_name = movie_list[choice - 1]
            movie_path = os.path.join(data_path, movie_name)
            data_dict = {
                'size': os.path.getsize(movie_path),
                'filename': movie_name
            }
            data_josn = json.dumps(data_dict)
            data_head = struct.pack('i', len(data_josn))
            client.send(data_head)
            client.send(data_josn.encode('utf8'))
            with open(movie_path, 'rb') as f:
                for line in f:
                    client.send(line)

  

上一篇:hive的随机函数rand()


下一篇:调度器31—Linux-5.10 调度相关trace分析技巧汇总