首页 > 其他分享 >33socket套接字/黏包问题

33socket套接字/黏包问题

时间:2023-09-11 17:26:04浏览次数:46  
标签:socket 黏包 send client print 接字 recv 33socket 服务端

socket套接字

#需求:编写一个cs架构的程序 实现数据交互
    思考:需要编写代码操作OSI七层 相当的复杂
  由于操作OSI七层是所有cs架构的程序都需要经历的过程 所以有固定的模块
  socket套接字是一门技术
  socket模块>>>:提供了快捷方式 不需要自己处理每一层
"""
以后我们写软件连socket的影子都看不到 因为被封装起来
socket是最底层的原理 很多框架都封装了 其实我们不需要深入研究
"""

socket模块

cs架构的软件无论是在编写还是运行
    都应该先考虑服务端 
      有了店运营了才可以接待客人
# 服务端
import socket


server = socket.socket()  # 买手机
"""
通过查看源码得知 
括号内不写参数默认就是基于网络的遵循TCP协议的套接字
"""
server.bind(('127.0.0.1', 8080))  # 插电话卡
"""
服务端应该具备的特征
    固定的地址
    ...  
127.0.0.1是计算机的本地回环地址 只有当前计算机本身可以访问
"""
server.listen(5)  # 开机
"""
半连接池(暂且忽略 先直接写 后面讲)
"""
sock, addr = server.accept()  # 等待并接听电话  没有人来就原地等待(程序阻塞)
"""
listen和accept对应TCP三次握手服务端的两个状态
"""
print(addr)  # 客户端的地址
data = sock.recv(1024)  # 听别人说话
print(data.decode('utf8'))
sock.send('你好啊'.encode('utf8'))  # 回复别人说的话
"""
recv和send接收和发送的都是bytes类型的数据
"""
sock.close()  # 挂电话
server.close()  # 关机

# 客户端
import socket


client = socket.socket()  # 产生一个socket对象
client.connect(('127.0.0.1', 8080))  # 根据服务端的地址链接

client.send(b'hello sweet heart!!!')  # 给服务端发送消息
data = client.recv(1024)  # 接收服务端回复的消息
print(data.decode('utf8'))

client.close()  # 关闭客户端

###########################
服务端与客户端首次交互
    一边是recv那么另一边必须是send  两边不能相同 否则就'冷战'了
###########################

通信循环

1.先解决消息固定的问题
    利用input获取用户输入
2.再解决通信循环的问题
    将双方用于数据交互的代码循环起来

while True:
    data = sock.recv(1024)  # 听别人说话
    print(data.decode('utf8'))
    msg = input('请回复消息>>>:').strip()
    sock.send(msg.encode('utf8'))  # 回复别人说的话
 
while True:
    msg = input('请输入你需要发送的消息>>>:').strip()
    client.send(msg.encode('utf8'))  # 给服务端发送消息
    data = client.recv(1024)  # 接收服务端回复的消息
    print(data.decode('utf8'))

代码优化及链接循环

1.发送消息不能为空
    统计长度并判断即可
2.反复重启服务端可能会报错>>>:address in use
  这个错在苹果电脑报的频繁 windows频率较少
  from socket import SOL_SOCKET,SO_REUSEADDR  #放在import socket之后的一句
  server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 在bind前加
以上两个代码直接复制粘贴,不需要特意去记忆
3.链接循环 """ 如果是windows 客户端异常退出之后服务端会直接报错 处理方式 异常处理 (try 和 except) 如果是mac或linux 服务端会接收到一个空消息 处理方式 len判断 """ 客户端如果异常断开 服务端代码应该重新回到accept等待新的客人 # 目前我们的服务端只能实现一次服务一个人 不能做到同事服务多个 学了并发才可以实现

半连接池

listen(5)
# py文件默认同一时间只能运行一次 如果想单独分开运行多次

# 半连接池
    设置的最大等待人数  >>>:  节省资源 提高效率
        除了正在运行的客人,外面还可以有五个客人等待

黏包问题

data1 = conn.recv(1024)   表示可以接收1024字节数的东西
print(data1)
data2 = conn.recv(1024)
print(data2)
data3 = conn.recv(1024)
print(data3)

client.send(b'hello')
client.send(b'jason')
client.send(b'kevin')
"""
三次打印的结果
  b'hellojasonkevin'
  b''
  b''
"""
# TCP协议的特点
    会将数据量比较小并且时间间隔比较短的数据整合到一起发送
  并且还会受制于recv括号内的数字大小(核心问题!!!)
  流式协议:跟水流一样不间断
    
"""
问题产生的原因其实是因为recv括号内我们不知道即将要接收的数据到底多大
如果每次接收的数据我们都能够精确的知道它的大小 那么肯定不会出现黏包
"""

思路: 
  困扰我们的核心问题是不知道即将要接收的数据多大
  如果能够精准的知道数据量多大 那么黏包问题就自动解决了!!!

解决黏包问题

方向:精准获取数据的大小
  
# struct模块
    import struct

  data1 = 'hello world!'
  print(len(data1))  # 12
  res1 = struct.pack('i', len(data1))  # 第一个参数是格式 写i就可以了
  print(len(res1))  # 4
  ret1 = struct.unpack('i', res1)
  print(ret1)  # (12,)


  data2 = 'hello baby baby baby baby baby baby baby baby'
  print(len(data2))  # 45
  res2 = struct.pack('i', len(data2))
  print(len(res2))  # 4
  ret2 = struct.unpack('i', res2)
  print(ret2)  # (45,)


  """
  pack可以将任意长度的数字打包成固定长度
  unpack可以将固定长度的数字解包成打包之前数据真实的长度


  思路:
      1.先将真实数据打包成固定长度的包
      2.将固定长度的包先发给对方
      3.对方接收到包之后再解包获取真实数据长度
      4.接收真实数据长度
  """

代码演示

recv括号内的数字尽量不要写太大 1024 2048 4096足够了
字典数据很难突破上面的数值

所以针对大文件的接收应该采用循环的形式一次接受一点点

 

标签:socket,黏包,send,client,print,接字,recv,33socket,服务端
From: https://www.cnblogs.com/Milk1/p/17693882.html

相关文章

  • linux里如何将一个文件和一个套接字绑定?
    要将一个文件和套接字绑定,你可以使用Linux中的命名管道(NamedPipe)来实现。命名管道是一种特殊类型的文件,可以用来在进程之间进行通信。你可以将命名管道作为一个文件来进行操作,同时将其连接到套接字以进行网络通信。以下是将文件内容输入到套接字的简单示例:创建一个命名管道:mkfifo......
  • 【Redis】Could not create server TCP listening socket __6379_ bind_ 在一个非套接
    问题描述:安装Redis,redis-server无法启动,报错。[34420]20Aug21:43:21.110#oO0OoO0OoO0OoRedisisstartingoO0OoO0OoO0Oo[34420]20Aug21:43:21.110#Redisversion=5.0.14.1,bits=64,commit=ec77f72d,modified=0,pid=34420,juststarted[34420]20Aug21:43:21.1......
  • 通过class字节码了解StringBuilder拼接字符串效率高的原因
    挺久没具体去看了,随手记一下吧。Stringstr="";for(inti=0;i<10;i++){str+=i;}这样的拼法,实际上从分析class的字节码来看,是在循环里面newStringBuffer对象,相当的耗。通过这样的分析,给新人解释,是最有效的了。还能提升一些了解java底层知识的兴趣。——《Java编程思......
  • java.sql.SQLException: 无法从套接字读取更多的数据
    本来订单的生成没有问题,但不知什么原因,报了一个这样的异常,致使订单不能生成[08-11-198:07:51:344CST]00000037JDBCExceptionEcouldnotinsert:[gmit.jzt.buying.databean.EOrderDO#122594][08-11-198:07:51:344CST]00000037JDBCExceptionE......
  • 直播系统源码协议探索篇(二):网络套接字协议WebSocket
     上一篇我们分析了直播平台的会话初始化协议SIP,他关乎着直播平台的实时通信和多方互动技术的实现,今天我们来讲另一个协议,叫网络套接字协议WebSocket,WebSocket基于TCP在客户端与服务器建立双向通信的网络协议,并且可以通过单个长连接实现。在直播系统源码平台已经成为人们获取知识......
  • 直播系统源码协议探索篇(二):网络套接字协议WebSocket
    上一篇我们分析了直播平台的会话初始化协议SIP,他关乎着直播平台的实时通信和多方互动技术的实现,今天我们来讲另一个协议,叫网络套接字协议WebSocket,WebSocket基于TCP在客户端与服务器建立双向通信的网络协议,并且可以通过单个长连接实现。在直播系统源码平台已经成为人们获取知识、放......
  • 什么是套接字
    1.客户端与服务端如何靠sock进行通信服务器端的返回的套接字是不是客户端的套接字服务器端创建监听套接字socket绑定bind监听listen提取accept客户端创建链接套接字链接socket是用来实现网络传输功能的,它负责不同主机进程之间的网络通信连接1.寻找结构体ip+......
  • 网络编程day01--socket套接字
    进程间通信-socket套接字基本特征:socket是一种接口技术,被抽象了一种文件操作,可以让同一计算机中的不同进程之间通信,也可以让不同计算机中的进程之间通信(网络通信)本地进程间通信编程模型:进程A                                        ......
  • linux 4 网络基础 POLL EPOLL epoll堆 线程池 udp 本地套接字
    Linux5day1.poll监听poll相对与sellect的优缺点优点:没有文件描述符1024的限制请求和返回是分离的如:selectread集合返回read集合缺点和select一样:每次都需要将需要监听的文件描述符从应用层拷贝到内核每次都需要将数组中的元素遍历一遍才知道那个变化了大量并发,少......
  • SQL2008 不用for xml 实现拼接字符串
    因为forxml有些特殊符号 不能作为分割符号,所以采用这种方式。如果是SQL2012的话 有自带的函数了--测试数据IFOBJECT_ID('tempdb..#tmp_Orgdata')ISNOTNULLDROPTABLE#tmp_OrgdataGO--GID分组IDSTRCOL字符串SELECTGID,StrColINTO#tmp_Orgdat......