服务端
@property (nonatomic, strong) GCDAsyncSocket *serverSocket; //服务端socket
@property (nonatomic, strong) GCDAsyncSocket *clientSocket;//客户端连接过来的socket
//创建服务端并启动服务
- (void)createLocalServer {
if (self.serverSocket == nil) {
self.serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSError *error = nil;
BOOL isa = [self.serverSocket acceptOnPort:[SocketServerPort integerValue] error:&error];
NSLog(@"----%d----",isa);
}
#pragma mark - 代理方法(GCDAsyncSocketDelegate)
//连接成功
- (void)socket:(GCDAsyncSocket *)sender didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
self.clientSocket = newSocket; //接收客户端连接过来的socket对象
self.clientSocket.delegate = self;//设置代理
//读取数据,以CRLFData结尾即表示是一条数据(以此来断开多个包一起发过来的粘包问题)
[self.clientSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}
//断开连接或连接失败
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSLog(@"-Socket断开连接--err = %@ --- code = %ld",err.localizedDescription,(long)err.code);
}
//读取数据
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
//接收到的消息处理
NSData *newData = [data subdataWithRange:NSMakeRange(0, data.length-2)];
//先尝试转字典
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:newData options:kNilOptions error:nil];
if (result) {
//处理获取到的字典数据
}
} else {
//如果字典转换失败,则尝试转换字符串
NSString *content = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding];
NSLog(@"--接收到的消息-- content = %@",content);
//接收到的字符串处理
}
//持续接收数据 以CRLFData结尾即表示是一条数据(以此来断开多个包一起发过来的粘包问题)
//如果不在读取完以后写这个方法,那就只读取一次数据,不会持续读取
[self.clientSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}
#pragma mark - 写数据成功回调
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(@"------发送完成---------");
}
#pragma mark - 发送数据
//发送文本类型消息
- (void)sendTextMessage:(NSString *)text {
if (text.length == 0 || text == nil) {
return;
}
if (!_clientSocket) {
NSLog(@"socket未连接");
return;
}
NSLog(@"发送的数据---(%@)",text);
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *printData = [[NSMutableData alloc] initWithData:data];
//拼接结束符
[printData appendData:[GCDAsyncSocket CRLFData]];
// withTimeout -1 : 无穷大,一直等
[self.clientSocket writeData:printData withTimeout:-1 tag:0];
}
//发送字典数据
- (void)sendTextMessageWithDict:(NSDictionary *)dict {
if (dict == nil || dict.count == 0) {
return;
}
if (!_clientSocket) {
NSLog(@"socket未连接");
return;
}
NSLog(@"发送的数据---(%@)",dict);
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
//字典转data结果判断
if (error) {
return;
}
NSMutableData *printData = [[NSMutableData alloc] initWithData:jsonData];
//拼接结束符
[printData appendData:[GCDAsyncSocket CRLFData]];
// withTimeout -1 : 无穷大,一直等
[self.clientSocket writeData:printData withTimeout:-1 tag:0];
}
客户端
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/if.h>
@property (nonatomic, strong) GCDAsyncSocket *socketClient;
/*
lo 本地回环 (Loopback)
en 无线网 (WiFi)
pdp_ip 蜂窝网络 (Cellular)
awdl 通信Wi-Fi (Apple Wireless Direct Link,用于AirDrop、AirPlay、GameKit 和 Apple Pencil )
utun 虚拟隧道 (VPN)
ipsec 虚拟隧道 (VPN)
llw 低延迟无线局域网(Low-latency WLAN)
*/
/// 获取ip地址
/// - Parameter isCellular: 是否获取蜂窝网络ip
- (NSString *)deviceIPAdressIsCellular:(BOOL)isCellular {
NSString *address = @"";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
success = getifaddrs(&interfaces);
if (success == 0) { // 0 表示获取成功
temp_addr = interfaces;
while (temp_addr != NULL) {
if( temp_addr->ifa_addr->sa_family == AF_INET) {
if (isCellular) {
if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"]) {
// 找到4G网络接口
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
} else {
// Check if interface is en0 which is the wifi connection on the iPhone
if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interfaces);
return address;
}
- (void)createLocalClient {
NSString *ip = [self deviceIPAdressIsCellular:NO];
NSString *port = @"84999";//设置自己的端口
if (self.socketClient == nil) {
self.socketClient = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
if (self.socketClient.isConnected == NO) {
BOOL isSuccess = [self.socketClient connectToHost:ip onPort:[port integerValue] error:nil];
if (!isSuccess) {
NSLog(@"连接失败");
}
}
} else {
BOOL isSuccess = [self.socketClient connectToHost:ip onPort:[port integerValue] error:nil];
if (!isSuccess) {
NSLog(@"连接失败");
}
}
}
#pragma mark - GCDAsyncSocketDelegate -
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
NSLog(@"Socket连接成功");
if (_socketClient) {
self.reconnectionsNumber = 0;
self.isConnect = YES;
// -1 永不失效
[_socketClient readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSLog(@"--%@-Socket断开连接--err = %@ --- code = %ld",[NSDate date],err.localizedDescription,(long)err.code);
//这里可以做尝试重连
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self createLocalClient];
});
}
//获取数据失败时,会被调用
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error {
NSLog(@"connection failed: %@",[error localizedDescription]);
}
#pragma mark - 读数据
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
//接收到的消息处理
NSData *newData = [data subdataWithRange:NSMakeRange(0, data.length-2)];
//先尝试转字典
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:newData options:kNilOptions error:nil];
if (result) {
//处理获取到的字典数据
}
} else {
//如果字典转换失败,则尝试转换字符串
NSString *content = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding];
NSLog(@"--接收到的消息-- content = %@",content);
//接收到的字符串处理
}
//持续接收数据 以CRLFData结尾即表示是一条数据(以此来断开多个包一起发过来的粘包问题)
//如果不在读取完以后写这个方法,那就只读取一次数据,不会持续读取
[self.socketClient readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}
#pragma mark - 写数据成功回调
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(@"------发送完成---------");
}
#pragma mark 发送文本类型消息
- (void)sendTextMessage:(NSString *)text {
if (text.length == 0 || text == nil) {
return;
}
if (!_socketClient) {
NSLog(@"socket未连接");
return;
}
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *printData = [[NSMutableData alloc] initWithData:data];
[printData appendData:[GCDAsyncSocket CRLFData]];
// withTimeout -1 : 无穷大,一直等
[self.socketClient writeData:printData withTimeout:-1 tag:0];
}
/// 发送数据(字典类型)
/// - Parameter dict: 发送的字典数据
- (void)sendTextMessageWithDict:(NSDictionary *)dict {
if (dict == nil || dict.count == 0) {
return;
}
if (!_socketClient) {
NSLog(@"socket未连接");
return;
}
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
if (error) {
return;
}
NSMutableData *printData = [[NSMutableData alloc] initWithData:jsonData];
[printData appendData:[GCDAsyncSocket CRLFData]];
// withTimeout -1 : 无穷大,一直等
[self.socketClient writeData:printData withTimeout:-1 tag:0];
}
网友评论