IOS 详解socket编程[oc]粘包、半包处理

IOS 详解socket编程[oc]粘包、半包处理

在做socket编程时,如果是做tcp连接,那就不可避免的会遇到粘包与半包的问题,粘包就是多组数据被一并接收了,粘在了一起,无法做划分;半包就是有数据接收不完整,无法处理。要解决粘包、半包的问题,一般在设计数据(消息)格式时会约定好一个字段专门用于描述数据包的长度,这样就使数据有了边界,依靠这个边界,就能把每组数据划分出来,数据不完整时也能获知数据的缺失。

(当然也可以把数据设计成定长数据,但这样不够灵活;或者用\n,\r这类字符作为数据划分依据,但不直观、不明确,同时也不灵活)

举个栗子:

消息=消息头+消息体。消息头用于描述消息本身的基本信息,消息体则为消息的具体内容

如上图所示,假如我们的一个消息是这么定义的

消息头 = msgId(4B)+version(2B)+len(4B),共占用10字节

消息体 =  len中描述的16字节长

所以这条消息的长度就是 26字节

可以看到,要想知道一条完整数据的边界,关键就是消息头中的len字段

假如我们现在接收到的数据是这样的:

这个情况下即包含了粘包,也出现了半包的情况,三个数据包粘在了一起,最后一个数据包没有接收完全,出现了半包的情况,看看代码如何处理

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
  while (_readBuf.length >= 10)//因为头部固定10个字节,数据长度至少要大于10个字节,我们才能得到完整的消息描述信息
  {
    NSData *head = [_readBuf subdataWithRange:NSMakeRange(0, 10)];//取得头部数据
    NSData *lengthData = [head subdataWithRange:NSMakeRange(6, 4)];//取得长度数据
    NSInteger length = [[[NSString alloc] initWithData:lengthData encoding:NSUTF8StringEncoding] integerValue];//得出内容长度
    NSInteger complateDataLength = length + 10;//算出一个包完整的长度(内容长度+头长度)
    if (_readBuf.length >= complateDataLength)//如果缓存中数据够一个整包的长度
    {
      NSData *data = [_readBuf subdataWithRange:NSMakeRange(0, complateDataLength)];//截取一个包的长度(处理粘包)
      [self handleTcpResponseData:data];//处理包数据
      //从缓存中截掉处理完的数据,继续循环
      _readBuf = [NSMutableData dataWithData:[_readBuf subdataWithRange:NSMakeRange(complateDataLength, _readBuf.length - complateDataLength)]];
    }
    else//如果缓存中的数据长度不够一个包的长度,则包不完整(处理半包,继续读取)
    {
      [_socket readDataWithTimeout:-1 buffer:_readBuf bufferOffset:_readBuf.length tag:0];//继续读取数据
      return;
    }
  }
  //缓存中数据都处理完了,继续读取新数据
  [_socket readDataWithTimeout:-1 buffer:_readBuf bufferOffset:_readBuf.length tag:0];//继续读取数据
}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • iOS App之间的通信 local socket

    之前看到一篇文章介绍到App之间的五种通信方式,它分别有URL Scheme,Keychain,UIPastedboard,UIDocumentInteractionController以及利用socket进行本地通信.前面4种都有用到过,也相对比较简单,几行代码的事.对于最后一种之前一直没用到过(原谅我还是个小白),所以今天试着写了下,这儿记录在这里和大家分享. 好了,废话不多说,开始: 首先,说下它的原理,其实很简单,一个App在本地的端口进行TCP的bind和listen,另外一个App在

  • iOS App通信之local socket示例

    之前看到一篇文章介绍到App之间的五种通信方式,它分别有URL Scheme,Keychain,UIPastedboard,UIDocumentInteractionController以及利用socket进行本地通信.前面4种都有用到过,也相对比较简单,几行代码的事.对于最后一种之前一直没用到过(原谅我还是个小白),所以今天试着写了下,这儿记录在这里和大家分享. 好了,废话不多说,开始: 首先,说下它的原理,其实很简单,一个App在本地的端口进行TCP的bind和listen,另外一个App在

  • iOS开发项目- 基于WebSocket的聊天通讯(2)

    公司项目需要开发一个类似QQ.微信的即时IM聊天功能,做到实时监控消息,需要用的技术是websocket,今天整理下语言聊天这块:其实语言聊天,包含两部分,录音和音乐播放,关于简单语言聊天功能如下图: 录音 在AVFoundation框架中有一个AVAudioRecorder类专门处理录音操作,它同样支持多种音频格式.与AVAudioPlayer类似,你完全可以将它看成是一个录音机控制类,下面是常用的属性和方法: 先来了解下AVAudioRecorder的常用属性: @property (rea

  • IOS开发网络篇—Socket编程详解

    一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象: 传输层.会话层.表示层和应用层则被称作主机层,是用户所面向和关心的内容. http协议对应于应用层 tcp协议对应于传输层 ip协议对应于网络层 三者本质上没有可比性.  何况HTTP协议是基于TCP连接的. TCP/IP是传输层协议,主要解决数据如何在网络中传输:而HTTP是应用

  • iOS应用中使用AsyncSocket库处理Socket通信的用法讲解

    用socket可以实现像QQ那样发送即时消息的功能.客户端和服务端需要建立长连接,在长连接的情况下,发送消息.客户端可以发送心跳包来检测长连接. 在iOS开发中使用socket,一般都是用第三方库AsyncSocket,不得不承认这个库确实很强大.下载地址CocoaAsyncSocket . 特性 AsyncSocket类是支持TCP的. AsyncUdpSocket是支持UDP的. AsyncSocket是封装了CFSocket和CFSteam的TCP/IP socket网络库.它提供了异步操

  • iOS开发项目- 基于WebSocket的聊天通讯(1)

    公司项目需要开发一个类似QQ.微信的即时IM聊天功能,做到实时监控消息,需要用的技术是websocket. 概述WebSocket: 1.1 为什么我们需要WebSocket这样的实时的通信协议? WebSocket是web通信方式的一种,像我们熟知的HTTP协议也是web通信方式的一种.但是我们知道HTTP协议是一种无状态的协议,其服务端本身不具备识别客户端的能力,必须借助外部的一些信息比如说session和cookie,才能与特定的客户端保持通信.也就是说我们所发送的每一个HTTP的请求都会

  • IOS中使用 CocoaAsyncSocket​

    Socket 如今在 iOS 里对 Socket 的应用慢慢多了起来,就一个即时通讯,很多应用都有集成,那即时通讯功能一般来说就肯定是基于 Socket 的,Socket 这个话题我一直谈论的比较少,一是由于看过一些 C/C++ 操作 Socket 的代码被吓到了一直还有心理阴影存在,二是工作里没怎么遇到相关的需求应用,所以也没有去深入研究相关内容. 还没接触过 Socket 编程肯定也会听说过这几个关键字:包.握手.连接.TCP.UDP 等等,Socket 编程的文章网上大把大把有,而作为一个

  • iOS 使用 socket 实现即时通信示例(非第三方库)

    其实写这个socket一开始我是拒绝的. 因为大家学C 语言和linux基础时肯定都有接触,客户端和服务端的通信也都了解过,加上现在很多开放的第三方库都不需要我们来操作底层的通信. 但是!还是想写.底层的东西最好了解下. 效果 由于5M的上传限制GIF可能看不清 我再截两张图吧 服务器 客户端A 客户端B 模型图 分析 由上图可以了解到服务器和客户端需要做哪些工作 服务器 抽象一点分为: 1.创建线程等待接收客户端的连接 2.接收并解析客户端发来的消息 3.给客户端发送消息 具体一点: 1.创建

  • IOS 详解socket编程[oc]粘包、半包处理

    IOS 详解socket编程[oc]粘包.半包处理 在做socket编程时,如果是做tcp连接,那就不可避免的会遇到粘包与半包的问题,粘包就是多组数据被一并接收了,粘在了一起,无法做划分:半包就是有数据接收不完整,无法处理.要解决粘包.半包的问题,一般在设计数据(消息)格式时会约定好一个字段专门用于描述数据包的长度,这样就使数据有了边界,依靠这个边界,就能把每组数据划分出来,数据不完整时也能获知数据的缺失. (当然也可以把数据设计成定长数据,但这样不够灵活:或者用\n,\r这类字符作为数据划分依

  • 详解C#编程获取资源文件中图片的方法

    详解C#编程获取资源文件中图片的方法 本文主要介绍C#编程获取资源文件中图片的方法,涉及C#针对项目中资源文件操作的相关技巧,以供借鉴参考.具体内容如下: 例子: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Drawing; namespace CL { public class RES { /

  • 详解Shell编程之变量数值计算(二)

    OK,数值运算(上)是我看完的一小部分,大概的结束脚本如下:(回顾~~) #!/bin/bash a=$1 b=$2 expr $1 + 1 &>/dev/null if [ "$?" -ne "0" ] then echo "请输入数字" exit 1 fi if [ "$#" -ne "2" ] then echo "请输入两个数字" exit 1 fi echo &q

  • 详解Shell编程之变量数值计算(一)

    如果要执行运算,那就少不了运算符,和其他的编程语言相似,shell也有很多的运算符如下: +.-.:代表着加号 和减号 或者,负号 *./.%:代表着乘号,除号,和取模. **   : 幂运算 ++.-- :表示着增加或者减少,它可以放在前置,也可以放在变量的结尾 !.||.&&.(取反)(或) (and) <.<=.>.>=  :比较符号,小于.小于等于.大于.大于等于 ==.!=.= :相等,不相等, =表示相等于 <<     >> 

  • 详解docker部署SpringBoot及替换jar包的方法

    关于docker的安装和使用,可以看看之前这两篇文章.docker kubernetes dashboard安装部署详细介绍和Docker如何使用link建立容器之间的连接.这篇文章主要介绍如何在docker上部署springboot项目.关于如何创建springboot项目可以看看这篇文章IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题 本文主要介绍docker部署springboot的三种方式,分别是:入门方式.jar包替换部署的方式和脚本部署方式,一步步来手把手教程.

  • 详解python编程slice与indices函数用法示例

    一般来说,内置的slice()函数会创建一个切片对象,可以用在任何允许进行切片操作的地方. 下面是slice的简介: # slice 两种用法 class slice(stop) class slice(start, stop[, step]) 返回一个表示由 range(start, stop, step) 所指定索引集的 slice对象. 其中 start 和 step 参数默认为 None. 切片对象具有仅会返回对应参数值(或其默认值)的只读数据属性 start, stop 和 step.

  • 从零开始学Python第八周:详解网络编程基础(socket)

    一,Socket编程 (1)Socket方法介绍 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 套接字是一个双向的通信信道的端点.套接字可能在沟通过程,进程之间在同一台机器上,或在不同的计算机之间的进程 要创建一个套接字,必须使用Socket模块的socket.socket()方法 在socket模块中的一般语法: s = socket.socket(sock

  • 详解Java编程中包package的内容与包对象的规范

    包的内容 包的内容应该仔细设计,使其只包含在功能上相关的类和接口.包中的类可以自由地访问该包中其他类的非私有成员,有些类甚至可能有足够的权限去访问其他类的内部细节,为了避免这样的类对类成员进行误操作,我们需要对类成员进行保护.任何没有被声明为private的成员都可以被同一个包中的其他所有类型访问,所以任何不相关的类之间的藕合程度都可能会比我们所期望的程度高. 包还为寻找有用的接口和类的程序员提供了逻辑分组的功能.由不相关的类组成的包使程序员很难分辨出哪些接口和类是有用的,而类的逻辑分组可以帮助

  • python socket网络编程步骤详解(socket套接字使用)

    一.套接字套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连接,如发送和接受数据.为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要.套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳.许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持.三种最流行的套接

  • 详解Python编程中包的概念与管理

    Python中的包 包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境. 考虑一个在Phone目录下的pots.py文件.这个文件有如下源代码: #!/usr/bin/python # -*- coding: UTF-8 -*- def Pots(): print "I'm Pots Phone" 同样地,我们有另外两个保存了不同函数的文件: Phone/Isdn.py 含有函数Isdn() Phone/G3.py 含有函数G3() 现

随机推荐