socket套接字及粘包问题

socket套接字

1、什么是socket

socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)

2、为什么要有socket

实现应用层以下的层的工作,提高开发效率

3、怎么使用socket

先导入socket模块,先启动服务端套接字,再启动客户端套接字

# 服务端

import socket
# 买手机
server = socket.socket()
# 绑定手机号(IP,port)
# IP单机模式是127.0.0.1,局域网内使用cmd中ipconfig查询IPV4
# port设置8000以后的数据
server.bind(('127.0.0.1', 9876))
# 设置半连接池
server.listen(4)
# 可接收多个客户端数据连接,实现循环通信
while True:
    # 接收客户端连接
    conn, addr = server.accept()
    # 查看对方地址
    print(addr)
    while True:
        # 捕获异常机制
        try:
            # 接收客户端发来的数据,可一次接收1024bytes的数据
            data = conn.recv(1024)
            if len(date) == 0:
                break
            if data.decode('utf-8') == 'q':
                break
            print(data.decode('utf-8'))
            # 向客户端发送消息
            send_data = input('请输入向客户端发送的数据:')
            conn.send(send_data.encode('utf-8'))
        # 捕获异常,并打印出错误信息
        except Exception as e:
            print(e)
            break
    # 挂电话
    conn.close()
# 客户端

import socket
# 买手机
client = socket.socket()
# 建立连接(IP,port)
client.connect(('127.0.0.1',9876))
while True:
    try:
        # 向对方发送数据
        data = input('请输入向服务端发送的数据')
        client.send((data.encode('utf--8')))
        # 接收对方发来的数据可设置一次接收的bytes数,并打印
        res_data = client.recv(1024)
        if len(res_data) == 0:
            break
        if res_data.decode('utf-8') == 'q':
            break
        print(res_data.decode('utf-8'))
    # 捕获异常,并打印出异常
    except Exception as e:
        print(e)
        break
client.close()

粘包问题

问题1:

无法确认对方发送过来数据大小

问题2:

在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送

解决:需要确认对方发送的数据大小

# 客户端
# 问题1
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    try:
        cmd = input('请输入向服务端发送的命令:')
        client.send(cmd.encode('utf-8'))
        # 接收服务端返回的数据
        # 由于不知道会返回多少个bytes所以有问题1
        date = client.recv(11910)
        print(len(date))
        print(date.decode('gbk'))
    except Exception as e:
        print(e)
        break
client.close()
# 客户端
# 问题2
# 时间间隔短,并数据量小的情况下,会将所有的数据一次性发送,接收时不知道具体有几个
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
# 服务端

import socket
import subprocess

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(4)
while True:
    conn, addr = server.accept()
    print(addr)

    while True:
        try:
            # 接收客户端的数据,具体值不知道多大,所有有可能不能完全接收,有可能浪费资源
            cmd = conn.recv(12)
            if len(cmd) == 0:
                break
            cmd = cmd.decode('utf-8')
            if cmd == 'q':
                break
            # 调用subprocess连接终端,对终端进行操作,并获取正确和错误的结果
            obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # 拿到结果,并打印
            result = obj.stdout.read() + obj.stderr.read()
            print(result.decode('gbk'))
            # 将结果返回给客户端
            conn.send(result)

        except Exception as e:
            print(e)
            break
    conn.close()

解决粘包问题

使用struct模块

struct 是一个python内置的模块,它可以将固定长度的数据,打包成固定格式的长度

模式:i:4,或其他模式

作用:将真实数据做成一个固定长度的报头,发送给服务端,服务端接收报头,然后进行解包,获取真实数据的长度,进行接收数据即可

import struct
data = input('请输入传的数据').strip()
data = data.encode('utf-8')
# 制作报头,需要 i 的字符串和传入数据的长度
header = struct.pack('i',len(data))
print(header)
print(len(header))

# 解包( i 的字符串和报头)获取真实长度,得到一个元组,拿到元组第一个数就是真实长度
res = struct.unpack('i', header)[0]
print(res)

# utf-8中一个中文是3个bytes,一个英文是1个bytes

客户端:

​ 1.先制作报头,并发送

​ 2.发送真实数据

服务端:

​ 1.接收报头,并且解包获取真实数据长度

​ 2.根据真实数据长度,接收真实数据

# 客户端
import socket
import struct

client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    try:
        cmd = input('请输入向服务端发送的命令')
        cmd_bytes = cmd.encode('utf-8')
        # 做一个报头
        header = struct.pack('i', len(cmd_bytes))
        # 发送报头
        client.send(header)
        # 发送真实数据
        client.send(cmd_bytes)
        # 接受服务端返回的报头
        reheader = client.recv(4)
        # 解包
        data_len = struct.unpack('i', reheader)[0]
        result = client.recv(data_len)
        print(result.decode('gbk'))
    except Exception as e:
        print(e)
        break
client.close()
# 服务端
import socket
import subprocess
import struct

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
    conn, addr = server.accept()
    while True:
        try:
            # 获取报头
            header = conn.recv(4)
            # 获取真实数据长度
            data_len = struct.unpack('i', header)[0]
            # 准备接受真实数据
            cmd = conn.recv(data_len)
            cmd = cmd.decode('utf-8')
            if cmd == 'q':
                break
            if len(cmd) == 0:
                break
            obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            result = obj.stdout.read() + obj.stderr.read()
            print(len(result))
            print(result.decode('gbk'))
            # 将结果返回给客户端
            header = struct.pack('i', len(result))
            conn.send(header)
            conn.send(result)
        except Exception as e:
            print(e)
            break
    conn.close()
# 客户端
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    # 伪装电影数据
    movie_name = input('请输入电影名称:')
    movie_len = 10000101
    send_dic = {
        'movie_name': movie_name,
        'movie_len': movie_len
    }
    # 序列化
    json_data = json.dumps(send_dic)
    # 制作报头
    json_bytes = json_data.encode('utf-8')
    header = struct.pack('i', len(json_bytes))
    # 发送报头
    client.send(header)
    # 发送真实数据
    client.send(json_bytes)


# 服务端
import socket
import json
import struct

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
    conn, addr = server.accept()
    print(addr)
    while True:
        try:
            # 接收报头
            header = conn.recv(4)
            # 解包获取真实长度
            json_len = struct.unpack('i', header)[0]
            # 接收真实长度
            json_bytes_data = conn.recv(json_len)
            json_data = json_bytes_data.decode('utf-8')
            # 反序列化得到数据
            back_dic = json.loads(json_data)
            print(back_dic)
        except Exception as e:
            print(e)
            break
    conn.close()

posted @ 2019-12-05 21:44  Mr沈  阅读(263)  评论(0编辑  收藏  举报