Socket 套接字和解决粘包问题

---恢复内容开始---

Socket 套接字:

什么是socket:

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实

就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口

就是全部,让Socket去组织数据,以符合指定的协议。

socket在OSI模型中的位置

二为什么需要socket

在标准的OIS模型中并没有规定说必须有socket层,也就是说不使用socket也能完成通讯,是的,的确如此!

那为什么需要socket呢?一个字 懒,程序员都是懒的!

我们发现还没有开始实现应用程序逻辑,就需要花大把时间来实现各种协议,太特么费事儿了,就有人专门把协议中一堆复杂的事情进行了封装,于是socket就诞生了!

有了socket以后,无需自己编写代码实现三次握手,四次挥手,ARP请求,打包数据等等,socket已经封装好了,只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

三socket的发展:

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

基于文件类型的套接字家族:

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族:

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于大部通讯都是网络通讯,所以大部分时候使用AF_INET)

python中的socket:

需明确:关于网络协议 和socket相关概念,对于所有编程语言都是一致的,区别仅仅是各编程语言的函数名称不同

TCP协议:

1.导入socket模块

import socket

2创建TCP套接字对象,函数定义如下

server = socket.socket(scoket.AF_INET,socket.SOCK_STREAM)

或者

server = socket.socket()里面不写就是默认TCP协议的

服务端的函数:

bind()绑定主机号加端口到套接字

127.0.0.1是本机回还地址,只能在本机适用。

listen()进入监听 可以可以放监听的客户端个数,也是半链接池,就是还没有完全通过三次握手的,填5就表示最大接收5个处于半链接状态,等链接断了就从这里拿一个出来,然后再进去,防止洪水攻击。

accept()被动接受客户端的链接,阻塞式等待链接的到来。

客户端的函数:

 connect 主动链接服务端

 connect_ex 提高健壮性,出错不会报异常,而是返回错误码。

公共:

recv()接收

send()发送

这2个要一一对应,客户端是发送服务端就要收,不然会阻塞。

粘包:

问题点:因为有2点一点就是tcp协议内部的优化机制,Nikon算法,会将数据量小河发送间隔短的数据打包一起发送给对方。二就是超出了接收方的最大接收字节,下次还会继续发,直到发完。

解决:

  服务端:

    1.先写一个发送给客户端的字典

    2.制作字典的报头

    3.发送字典的报头

    4.发送字典的数据

    5.发送真实数据

  客户端:

    1.先接受字典的报头长度

    2.解包得到字典的长度

    3.得到字典的数据

    4.从字典中获取真实数据的长度

    5.接收真实数据

服务端

import socket
import subprocess
import json
import struct
server = socket.socket()
server.bind((‘127.0.0.1‘,9696))
server.listen(5)
while True:
    conn,addr = server.accept()
    while True:
        try:
            data = conn.recv(1024).decode(‘utf-8‘)
            if len(data) == 0:break
            obj = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            msg = obj.stdout.read() + obj.stderr.read()
            dic = {‘name‘:"lw",‘file_size‘:len(msg)}
            json_dic = json.dumps(dic)
            dic_header = struct.pack(‘i‘,len(json_dic))  # 先产生字典的报头长度
            conn.send(dic_header)  # 先发送报头长度
            conn.send(json_dic.encode(‘utf-8‘))  # 发送字典数据
            conn.send(msg) # 发送真实数据
        except ConnectionResetError:
            break
    conn.close()

客户端

import socket
import struct
import json

client = socket.socket()
client.connect_ex((‘127.0.0.1‘,9696))
while True:
    cmd = input(‘请输入指令:‘).strip()
    if len(cmd) == 0:continue
    client.send(cmd.encode(‘utf-8‘))
    data = client.recv(4)  # 获得字典报头大小
    dic_head = struct.unpack(‘i‘,data) [0] # 获得字典的长度
    json_dic = client.recv(dic_head) #接收字典的数据
    json_bytes = json.loads(json_dic.decode(‘utf-8‘))  # 反序列化处理
    recv_size = 0
    recv_data = b‘‘
    while recv_size < json_bytes.get(‘file_size‘):
        data = client.recv(1024)
        recv_data+=data
        recv_size+=len(data)

    print(recv_data.decode(‘gbk‘))

---恢复内容结束---

原文地址:https://www.cnblogs.com/xinfan1/p/11318168.html

时间: 2024-07-29 16:57:12

Socket 套接字和解决粘包问题的相关文章

socket大文件传输(解决粘包)

解决粘包 模块struct struct.pack(type,num) type:是num的类型 num :是一个数字 r = struct.pack 把一个数字打包成一个四字节的bytes struct.unpack(type,r) 功能:解包,把r解成原数字,结果是一个元组,原数字在元组的下标位0的位置 #解决粘包:原理是在服务器接收到字典长度后,根据字典长度去recv字典中的内容,就不会造成recv最后一次接收完后剩下的空间留给部分文件内容所造成字典内容和文件内容黏在一起 #实现文件的上传

粘包产生的原因 socket 基于tcp实现远程执行命令(解决粘包)low

# 粘包产生的原因 # 粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的. # 基于tcp协议的套接字会有粘包现象,而基于udp协议的套接字不会产生粘包现象 # tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住:而udp是基于数据报的,即使你输入的是空内容,那也不是空消息,udp协议会帮你封装上消息头(ip+端口的方式),这样就有了消息办界 # 两种情况下会发生粘包 # 1.发送端需要等缓冲区满才发送

基于UDP协议的socket套接字编程 基于socketserver实现并发的socket编程

基于UDP协议 的socket套接字编程 1.UDP套接字简单示例 1.1服务端 import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 建立一个UDP协议的服务器 server.bind(("127.0.0.1",8080)) while True: data,addr = server.recvfrom(1024) server.sendto(data.upper(),addr) server

socket套接字编程 HTTP协议

socket套接字编程  套接字介绍  1. 套接字 : 实现网络编程进行数据传输的一种技术手段  2. Python实现套接字编程:import  socket  3. 套接字分类 >流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案.(面向连接--tcp协议--可靠的--流式套接字)  >数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案.(无连接--udp协议--不可靠--数据报套接字) tcp套接字编程  服务端流程  

基于UDP协议的socket套接字编程

基于UDP协议的socket套接字编程 一.UDP套接字简单示例 1.1 服务器 import socket server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 数据报协议->UDP server.bind(('127.0.0.1', 8080)) while True: data, client_addr = server.recvfrom(1024) print('===>', data, client_addr) ser

网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

TCP协议:三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求 3:客户端接收到服务端发来的请求,返回接成功给服务端,完成双向连接 第一客戶向服务端发送请求,请求建立连接 服务端同客户端的请求,并同时向客户端发送建立 连接的请求,最后客户端同意后建立 双向连接. C ----> S C <---- S - 反馈机制: 客户端往服务端发送请求,服务端必须返回响应, 告诉客户

python基础--socket套接字、粘包问题

本地回环地址:127.0.0.1 简易版服务端: import socket ? server = socket.socket() # 就比如买了一个手机 server.bind(("127.0.0.1",8080)) # bind中绑定的是IP地址和端口号,注意是一个元组,就比如,将手机卡,插入了手机 server.listen(5) # 半连接池,最大等待连接数为5个,就比如开机 conn,address = server.accept() # 接听电话等着别人给你打电话 ? da

Socket解决粘包问题1

粘包是指发送端发送的包速度过快,到接收端那边多包并成一个包的现象,比如发送端连续10次发送1个字符'a',因为发送的速度很快,接收端可能一次就收到了10个字符'aaaaaaaaaa',这就是接收端的粘包. 可能我们在平时练习时没觉的粘包有什么危害,或者通过把发送端发送的速率调慢来解决粘包,但在实时通信中,发送端常常是单片机或者其他系统的信息采集机,它们的发送速率是无法控制的,如果不解决接收端的粘包问题,我们无法获得正常的信息. 就以我自己正在做的项目来说,接收端是一台单频指标测量仪,它会把当前测

c# socket 解决粘包,半包

处理原理: 半包:即一条消息底层分几次发送,先有个头包读取整条消息的长度,当不满足长度时,将消息临时缓存起来,直到满足长度再解码 粘包:两条完整/不完整消息粘在一起,一般是解码完上一条消息,然后再判断是否有剩余字节,有的话缓存起来,循环半包处理 客户端接收代码: private void callReceived(object sender, SocketAsyncEventArgs args) { var socket = sender as Socket; var bb = args.Use