处理Socket数据粘包问题

处理数据粘包问题思路如下:

socket数据就像一个水管,水管的水是一股一股流出来的

 (假设数据是有一个一个的字典组成的,字典与字典之前用\n(换行符)区分)

 例如:

 其中一条数据为: {"key","value"}\n

 收到的数据也可能为:

 ........

 {"key","value"}\n

 {"key","value"}\n

 {"key","value"}\n

 {"key","value"}\n

 {"key",

 

 会出现不完整的现象,因为socket发数据是一安次区分的,每次发送的数据大小可能是20KB超过的部分自然会被去掉,然后在下一次发送

 下一次收到的数据一定是:


 "value"}\n

 {"key","value"}\n

 {"key","value"}\n

 {"key","value"}\n

 ........

 只要在下一次接收数据时和上一次接收的数据拼接到一块就能获得完整的数据;

 具实现方法是:

 接收到一个数据后,先把这次的数据能提炼出来的字典提炼出来,显示给UI;然后把提炼出来的部分删掉,把尾巴留下来;下次再来一股数据时和上一次剩下的尾巴拼接在一块,继续处理,这样一直循环下去.....

代码部分如下

一、建立一个工具类 命名为DataControl.h

定义两个数据组分别保存二进制文件和处理好数据

@interface DataControl ()
{
    //保存二级制文件数据
    NSMutableData *_currentData;
    //保存有用的字符串数据
    NSMutableArray *_lastMessages;
}
@end

添加并返回处理好的新数据方法

-(void)appendingData:(id)data newData:(SocketDataBlock)block
{
    //1、拼接二进制数据
    [_currentData appendData:data];
    
    //2、转化成字符串
    NSString *string = [[NSString alloc] initWithData:_currentData encoding:NSUTF8StringEncoding];
    
    NSLog(@"socket 收到的数据data = %@",string);
    
    //3、分割字符串
    NSArray *stringArr = [string componentsSeparatedByString:@"\n"];
    NSMutableArray *usefulStringArr = [NSMutableArray new];
    
    //4、获取有用的字符串
    for (NSString *str in stringArr) {
        if ([str hasPrefix:@"{"] && [str hasSuffix:@"}"]) {
            [usefulStringArr addObject:str];
        }
    }
    
    //5、判断有没有新的字符串
    NSMutableArray *newStringArr = [NSMutableArray new];
    for (NSString *str in usefulStringArr) {
        if (![_lastMessages containsObject:str]) {
            [newStringArr addObject:str];
        }
    }
    //6、返回新的字符串 保存老的数组
    _lastMessages = usefulStringArr;
    block([self modelArrFrom:newStringArr]);
    _currentData = data;
}
/**
 数模转换
 */
-(NSMutableArray*)modelArrFrom:(NSMutableArray*)stringArr
{
    NSMutableArray *modelArr = [NSMutableArray new];
    for (NSString *string in stringArr) {
        SocketModel *model = [SocketModel mj_objectWithKeyValues:string];
        [modelArr addObject:model];
    }
    return modelArr;
}

这样就可以方便的处理socket数据,本文只是以最简单的例子,具体使用中可能会有偏差,但具体思路不会有问题。


参考阅读:

 利用GCDAsyncSocket实战经验

  Socket 断线重连问题

代码文件:

  代码文件



发布了93 篇原创文章 · 获赞 21 · 访问量 25万+
展开阅读全文

c# Socket,tcp接收时会

09-01

private void RecMsg(object sokConnectionparn) { Socket sokClient = sokConnectionparn as Socket; while (true) { byte[] arrMsgRec = new byte[1024 * 1024 * 3+3]; // 将接受到的数据存入到输入 arrMsgRec中; int length = -1; try { length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度; } catch (SocketException se) { ShowMsg("异常:" + se.Message); dictSocket.Remove(sokClient.RemoteEndPoint.ToString()); dictThread.Remove(sokClient.RemoteEndPoint.ToString()); DeleteLib(sokClient.RemoteEndPoint.ToString()); break; } catch (Exception e) { ShowMsg("异常:" + e.Message); dictSocket.Remove(sokClient.RemoteEndPoint.ToString()); dictThread.Remove(sokClient.RemoteEndPoint.ToString()); DeleteLib(sokClient.RemoteEndPoint.ToString()); break; } try { if (arrMsgRec[0] == 0) // 表示接收到的是数据; { string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);// 将接受到的字节数据转化成字符串; ShowMsg(strMsg); } if (arrMsgRec[0] == 1) // 表示接收到的是文件; { filesource = sokClient.RemoteEndPoint.ToString(); //var i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length-3); if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("FileName")) { string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1); bpp.FileName = strMsg.Split(':')[1]; bpp.Index = 0; savepath = ""; savepath = Path.Combine(savepath, bpp.FileName); } else if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("PackageCount")) { string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1); bpp.PackageCount = int.Parse(strMsg.Split(':')[1]); } else if (arrMsgRec[1] == 22 && arrMsgRec[2] == 33) { //int i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length - 3); byte[] buffer = new byte[length - 3]; Buffer.BlockCopy(arrMsgRec, 3, buffer, 0, buffer.Length); if (!string.IsNullOrEmpty(bpp.FileName)) { Thread fw = new Thread(() => FileWrite(savepath, bpp.Index, 1024 * 1024 * 3, buffer.Length, buffer)); fw.IsBackground = true; fw.Start(); } } else { stringtobyte("Err:" + bpp.Index.ToString(), 1); dictSocket[filesource].Send(stringtobyte("Err:" + bpp.Index.ToString(), 1)); } } } catch(Exception ex) { //MessageBox.Show(ex.Message); } } } 用这个作为后台线程接收,然后发文件(客户端线程分包自动发的)的同时传输信息的话会粘包吧,好像是这个说法,就是那一包文件数据会收不到,然后聊天信息会出现乱码,求教怎么解决,新手实在搞不定- -谢谢. 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览