前一段的做的项目使用的是Sockt TCP协议,在这家公司一直都是用的UDP,这一次做的集成控制平台,对数据的完整性要求比较严格,数据量也比较大所以使用了TCP协议,由于是第一次做TCP协议前前后后弄了一整天,
当数据量大的时候一般服务端会分包发送数据,但是我这后台使用的是一次性将数据都发送出去,由于数据太大,tcp会自己将数据拆分发送,我在刚开始的时候总是不能一次将数据接收完,是一个不完整的数据,数据都是以 “\n” 作为结束的标记,最后查了很多博客才弄好,下面是我的源码贴出来,希望看到的对你有帮助,
我的Socket TCP是基于第三方GCDAsyncSocket https://github.com/robbiehanson/CocoaAsyncSocket实现的,这个第三方封装的很好,用起来很方便
这里是我写的一个单例类方便数据的读取
//
// DataHelp.h
// N-mix
//
// Created by chenq@kensence.com on 16/4/21.
// Copyright © 2016年 times. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
@interface DataHelp : NSObject<GCDAsyncSocketDelegate>
@property (nonatomic ,strong)GCDAsyncSocket *ClientSocket;//Socket
@property (nonatomic ,strong)NSMutableData *mutData; //接受的数据
//创建单例
+(DataHelp *)shareData;
//连接服务器,在这我写一个方法方便使用
- (void)CreatTcpSocketWithIP:(NSString *)Host port:(uint16_t)Port;
@end
//
// DataHelp.m
// N-mix
//
// Created by chenq@kensence.com on 16/4/21.
// Copyright © 2016年 times. All rights reserved.
//
#import "DataHelp.h"
#import <UIKit/UIKit.h>
@interface DataHelp ()
@property (nonatomic ,strong)NSMutableArray *mutArray; //临时数组
@property (nonatomic ,strong)NSMutableArray *MutTXArray;
@end
@implementation DataHelp
//GCD单例方法
+ (DataHelp *)shareData
{
static DataHelp * help = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
help = [DataHelp new];
});
return help;
}
//创建连接
- (void)CreatTcpSocketWithIP:(NSString *)Host port:(uint16_t)Port
{
//创建一个队列,等待接收数据
dispatch_queue_t Queue = dispatch_queue_create("client tcp socket", NULL);
//创建一个tcp和服务端通讯
_ClientSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:Queue socketQueue:nil];
//初始化一个Nsmutabledata用于接收数据
_mutData = [NSMutableData data];
//连接服务器 60s连接不上出错服务器在线时
NSString *host = Host;
uint16_t port = Port;
// _ClientSocket.delegate = self; //这里不用再写
//连接服务器
[_ClientSocket connectToHost:host onPort:port withTimeout:-1 error:nil];
}
#pragma mark ===代理方法
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
//连接成功
NSLog(@"连接成功");
[_ClientSocket readDataWithTimeout:-1 tag:200]; //读取数据,只有读取数据后面的代理方法DidReaddata这个代理方法才会走。
}
//连接失败重连
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
//这里我是将IP port都保存在本地从本地直接去取
NSString *host1 = [[NSUserDefaults standardUserDefaults]objectForKey:@"HostKey"];
NSString *port1 = [[NSUserDefaults standardUserDefaults]objectForKey:@"PortKey"];
//重新连接(如果连接失败就会自动继续连接)
unsigned short utfString = [port1 integerValue];
[_ClientSocket connectToHost:host1 onPort:utfString withTimeout:10 error:nil]; //这里的10是代表10秒后会继续执行,写成-1也可以代表不延时
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"消息发送成功");
//消息发送成功调用,这里必须调用,不然后面的DidReadData不会执行
[_ClientSocket readDataWithTimeout:-1 tag:200];
}
//接受到服务器返回的数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *dataString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (_mutData == nil) {
_mutData = [[NSMutableData alloc]init];
}else
{
//拼接接受到的数据
[_mutData appendData:data];
//标记结束符 这里是以(“\n”)大多是以(\r\n),这个和后台的兄弟问
NSRange rang = [dataString rangeOfString:@"\n"];
if (rang.location != NSNotFound) { //一直向后找
//由于接受到的数据都是data类型,这里转为string
NSString *String = [[NSString alloc]initWithData:_mutData encoding:NSUTF8StringEncoding];
NSLog(@"%@",String);
//从string转为data
NSData *data = [String dataUsingEncoding:NSUTF8StringEncoding];
//再从data转回dictionary
NSDictionary *AlDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
}
//这里调用和上面的一个一次,
[_ClientSocket readDataWithTimeout:-1 tag:200];
}
- (void)dealloc
{
[_ClientSocket disconnect];
_ClientSocket = nil;
}