套字节(socket)

Posted sweet-i

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了套字节(socket)相关的知识,希望对你有一定的参考价值。

socket(套接字):

  是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写

和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组。

传输层实现端到端的通信,因此,每一个传输层连接有两个端点。那么,传输层连接的端点是什么呢?不是主

机,不是主机的ip地址,不是应用进程,也不是传输层的协议端口。传输层连接的端点叫做套接字(socket)。

所谓套接字,实际上是一个通信端点,每个套接字都有一个套接字序号,包括主机的IP地址与一个16位的主机端

口号,即形如(主机IP地址:端口号)。例如,如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)。

技术图片

代码实现:

# 服务端.py文件

import socket

server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
server.bind((127.0.0.1,8080))  # bind((host,port))  插电话卡  绑定ip和端口
server.listen(5)  # 开机    半连接池
conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
print(data)
conn.send(bhello baby~)  # 给别人回话

conn.close()  # 挂电话
server.close()  # 关机





# 客户端.py文件
import socket

client = socket.socket()  # 拿电话
client.connect((127.0.0.1,8080))  # 拨号   写的是对方的ip和port
client.send(bhello world!)  # 对别人说话
data = client.recv(1024)  # 听别人说话
print(data)

client.close()  # 挂电话

 

TCP黏包问题:

TCP为了保证可靠传输,尽量减少额外开销(每次发包都要验证),因此采用了流式传输,面向流的传输,相

对于面向消息的传输,可以减少发送包的数量,从而减少了额外开销。但是,对于数据传输频繁的程序来讲,

使用TCP可能会容易粘包。当然,对接收端的程序来讲,如果机器负荷很重,也会在接收缓冲里粘包。这样,

就需要接收端额外拆包,增加了工作量。因此,这个特别适合的是数据要求可靠传输,但是不需要太频繁传输

的场合(两次操作间隔100ms,具体是由TCP等待发送间隔决定的,取决于内核中的socket的写法)

TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前

一包数据的尾。出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。

TCP黏包问题演示:

# 服务端.py代码演示:

import socket

server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
server.bind((127.0.0.1,8080))  # bind((host,port))  插电话卡  绑定ip和端口
server.listen(5)  # 开机    半连接池
conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
data = conn.recv(5)  # 听别人说话 接收1024个字节数据          阻塞
print(data)
data = conn.recv(5)  # 听别人说话 接收1024个字节数据          阻塞
print(data)
data = conn.recv(4)  # 听别人说话 接收1024个字节数据          阻塞
print(data)





# 客户端.py代码演示:

import socket

client = socket.socket()  # 拿电话
client.connect((127.0.0.1,8080))  # 拨号   写的是对方的ip和port
client.send(bhello)
client.send(bworld)
client.send(bbaby)

 

解决黏包问题:

 对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,

TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满。这种编程设置方法虽然

可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议

使用。

 对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其

及时接收数据,从而尽量避免出现粘包现象。这种方法只能减少出现粘包的可能性,但并不能完全避免粘包,

当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接

收,从而导致粘包。

 由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。这种

方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。

一种比较周全的对策是:接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开;具体操

作为:

  服务端
    1.先制作一个发送给客户端的字典
    2.制作字典的报头
    3.发送字典的报头
    4.发送字典
    5.再发真实数据

  客户端
    1.先接受字典的报头
    2.解析拿到字典的数据长度
    3.接受字典
    4.从字典中获取真实数据的长度
    5.接受真实数据

代码演示实现:

#  服务端代.py码演示:

import socket
import subprocess
import struct
import json

server = socket.socket()
server.bind((127.0.0.1,8080))
server.listen(5)
while True:
    conn, addr = server.accept()
    while True:
        try:
            cmd = conn.recv(1024)
            if len(cmd) == 0:break
            cmd = cmd.decode(utf-8)
            obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            res = obj.stdout.read() + obj.stderr.read()
            d = name:jason,file_size:len(res),info:asdhjkshasdad
            json_d = json.dumps(d)
            # 1.先制作一个字典的报头
            header = struct.pack(i,len(json_d))
            # 2.发送字典报头
            conn.send(header)
            # 3.发送字典
            conn.send(json_d.encode(utf-8))
            # 4.再发真实数据
            conn.send(res)
            # conn.send(obj.stdout.read())
            # conn.send(obj.stderr.read())
        except ConnectionResetError:
            break
    conn.close()



# 客户端.py代码演示:
import socket
import struct
import json

client = socket.socket()
client.connect((127.0.0.1,8080))
while True:
    msg = input(>>>:).encode(utf-8)
    if len(msg) == 0:continue
    client.send(msg)
    # 1.先接受字典报头
    header_dict = client.recv(4)
    # 2.解析报头 获取字典的长度
    dict_size = struct.unpack(i,header_dict)[0]  # 解包的时候一定要加上索引0
    # 3.接收字典数据
    dict_bytes = client.recv(dict_size)
    dict_json = json.loads(dict_bytes.decode(utf-8))
    # 4.从字典中获取信息
    print(dict_json)
    recv_size = 0
    real_data = b‘‘
    while recv_size < dict_json.get(file_size):  # real_size = 102400
        data = client.recv(1024)
        real_data += data
        recv_size += len(data)
    print(real_data.decode(gbk))

 

连接循环+通讯循环:

# 服务端.py代码演示:
import socket

"""
服务端
    固定的ip和port
    24小时不间断提供服务
"""
server = socket.socket()  # 生成一个对象
server.bind((127.0.0.1,8080))  # 绑定ip和port
server.listen(5)  # 半连接池

while True:
    conn, addr = server.accept()  # 等到别人来  conn就类似于是双向通道
    print(addr)  # (‘127.0.0.1‘, 51323) 客户端的地址
    while True:
        try:
            data = conn.recv(1024)
            print(data)  # b‘‘  针对mac与linux 客户端异常退出之后 服务端不会报错 只会一直收b‘‘
            if len(data) == 0:break
            conn.send(data.upper())
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()



# 客户端.py代码演示


import socket

client = socket.socket()
client.connect((127.0.0.1,8080))
while True:
    msg = input(>>>:).encode(utf-8)
    if len(msg) == 0:continue
    client.send(msg)
    data = client.recv(1024)
    print(data)

 

struct模块:

struct会按照指定格式讲python数据转换为字符串,该字符串为字节流,比如网络传输时不能传输int,因此先将int转换

为字节流,然后再发送;但是它会按照指定格式将字节流转换为python指定的数据类型,处理二进制数据,如

果使用struct来处理文件的话,需要用“wb”;“rb”以二进制读写的方式来处理文件。

该对象可以根据格式化字符串的格式来读写二进制数据。第一个参数(格式化字符串)可以指定字节的顺序。

默认是根据系统来确定,也提供自定义的方式,只需要在前面加上特定字符即可。首先将数据对象放在了一个

元组中,然后创建一个Struct对象,并使用pack()方法打包该元组;最后解包返回该元组。

当打包或者解包是,需要按照特定的方式来打包或者解包,该方式就是格式化字符串,它指定了数据类型,除

此之外还用于控制字节顺序、大小和对其方式的特殊字符。

import struct

res = akdjsladlkjafkldjfgsdafhjksdfhfdgfdsgdfgssgddklsajkldsa
print(最原始的,len(res))
# 当原始数据特别大的时候 i模式打包不了 需要更换模式?
# 如果遇到数据量特别大的情况 该如何解决?
d = 
    name:jason,
    file_size:345543543534535452453453245654654656543455,
    info:为大家的骄傲

import json
json_d = json.dumps(d)
print(len(json_d))

res1 = struct.pack(i,len(json_d))
print(len(res1))
res2 = struct.unpack(i,res1)[0]
print(解包之后的,res2)

 

以上是关于套字节(socket)的主要内容,如果未能解决你的问题,请参考以下文章

python之远控工具

用socket发送接收数据,但每次接收的数据字节长度都大于发送的25个字节?

C++socket编程,数据转为网络字节序的问题htons

python socket 编程

socket网络套节字---聊天室

TCP编程(字节读写)- Socket 网络应用