Explanation of the use of AsyncSocket libraries in iOS applications to handle Socket communication
- 2020-06-03 08:28:32
- OfStack
socket enables instant messaging like QQ. The client and server need to establish a long connection and, in the case of a long connection, send a message. The client can send a heartbeat packet to detect a long connection.
socket is used in iOS development, and AsyncSocket is generally used in the third library, which I have to admit is quite powerful. Download from CocoaAsyncSocket
.
features
The AsyncSocket class supports TCP.
AsyncUdpSocket is for UDP.
AsyncSocket is an TCP/IP socket network library that encapsulates CFSocket and CFSteam. It provides asynchronous operations, complete delegate-based support for native cocoa classes. It has the following characteristics:
AsyncUdpSocket is the UDP/IP socket network library, packaged from CFSocket. It works much like the TCP version, except that it works with UDP. It includes non-blocking queue-based send and receive operations, full delegate support, ES47en-based, self-contained classes, and support for IPV4 and IPV6.
AsyncSocket can be used to do a layer of encapsulation, according to the requirements of several interfaces out. For example: connect, disconnect, send a message, and so on. There are also messages received, which can be sent through notifications, agents, block, and so on.
Generally speaking, a user only needs to establish a long connection to socket, so singleton classes can be used for ease of use.
Define a single-column class: LGSocketServe
LGSocketServe.h
//
// LGSocketServe.h
// AsyncSocketDemo
//
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
@interface LGSocketServe : NSObject<AsyncSocketDelegate>
+ (LGSocketServe *)sharedSocketServe;
@end
LGSocketServe.m
//
// LGSocketServe.m
// AsyncSocketDemo
//
#import "LGSocketServe.h"
@implementation LGSocketServe
static LGSocketServe *socketServe = nil;
#pragma mark public static methods
+ (LGSocketServe *)sharedSocketServe {
@synchronized(self) {
if(socketServe == nil) {
socketServe = [[[self class] alloc] init];
}
}
return socketServe;
}
+(id)allocWithZone:(NSZone *)zone
{
@synchronized(self)
{
if (socketServe == nil)
{
socketServe = [super allocWithZone:zone];
return socketServe;
}
}
return nil;
}
@end
Establish the socket long connection
LGSocketServe.h
@property (nonatomic, strong) AsyncSocket *socket; // socket
// socket The connection
- (void)startConnectSocket;
LGSocketServe.m
// Set your own
#define HOST @"192.168.0.1"
#define PORT 8080
// Setting connection timeout
#define TIME_OUT 20
- (void)startConnectSocket
{
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
[self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
if ( ![self SocketOpen:HOST port:PORT] )
{
}
}
- (NSInteger)SocketOpen:(NSString*)addr port:(NSInteger)port
{
if (![self.socket isConnected])
{
NSError *error = nil;
[self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error];
}
return 0;
}
Macro definition 1 HOST, PORT, TIME_OUT, startConnectSocket method. This time to set 1 AsyncSocket agent AsyncSocketDelegate. When the long connection is successful, it will call:
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
// This is the asynchronous return of connection success,
NSLog(@"didConnectToHost");
}
The heartbeat
LGSocketServe.h
@property (nonatomic, retain) NSTimer *heartTimer; // Heart meter
LGSocketServe.m
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
// This is the asynchronous return of connection success,
NSLog(@"didConnectToHost");
// Long connections are detected by sending messages continuously through a timer
self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
[self.heartTimer fire];
}
// The heartbeat connection
-(void)checkLongConnectByServe{
// Sends a fixed but message to the server to detect a long connection
NSString *longConnect = @"connect is here";
NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:1 tag:1];
}
In the callback method with a successful connection, start the timer and send a fixed message to the server every 2 seconds to detect the long connection. (This is based on the needs of the server)
disconnect
1. The user disconnects manually
LGSocketServe.h
// Disconnect the socket The connection
-(void)cutOffSocket;
LGSocketServe.m
-(void)cutOffSocket
{
self.socket.userData = SocketOfflineByUser;
[self.socket disconnect];
}
cutOffSocket is when the user disconnects and does not attempt to reconnect.
2, wifi disconnect, socket disconnect
LGSocketServe.m
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(@" willDisconnectWithError %ld err = %@",sock.userData,[err description]);
if (err.code == 57) {
self.socket.userData = SocketOfflineByWifiCut;
}
}
When wifi is disconnected, it will call back onSocket:willDisconnectWithError: method, ES118en. code == 57, setting self. socket. userData = SocketOfflineByWifiCut.
Reconnect the
When socket is disconnected, it will be called back:
LGSocketServe.m
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(@"7878 sorry the connect is failure %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// The server is disconnected and reconnected
[self startConnectSocket];
}
else if (sock.userData == SocketOfflineByUser) {
// If disconnected by the user, do not reconnect
return;
}else if (sock.userData == SocketOfflineByWifiCut) {
// wifi Disconnect, do not reconnect
return;
}
}
In the onSocketDidDisconnect callback method, self.socket.userData is used to determine if a reconnection is needed.
Send a message
LGSocketServe.h
// Send a message
- (void)sendMessage:(id)message;
LGSocketServe.m
// Set write timeout -1 Indicates that a timeout will not be used
#define WRITE_TIME_OUT -1
- (void)sendMessage:(id)message
{
// Send data like a server
NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:cmdData withTimeout:WRITE_TIME_OUT tag:1];
}
// Call back after sending the message successfully
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
}
After sending the message successfully, onSocket:didWriteDataWithTag: is called, in which the message can be read.
Receive a message
LGSocketServe.m
// Set read timeout -1 Indicates that a timeout will not be used
#define READ_TIME_OUT -1
#define MAX_BUFFER 1024
// Call back after sending the message successfully
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// Read the message
[self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
}
// Call back after receiving the message successfully
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// When the server returns a large amount of message data, it may return multiple times. So when you read the message, set MAX_BUFFER Represents the maximum number of reads per time, when data.length < MAX_BUFFER We think it might be acceptance 1 A complete message before parsing
if( data.length < MAX_BUFFER )
{
// Receive result parsing ...
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@",dic);
// The parsed messages can be sent through notifications, proxies, block Come out,
}
[self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
The message is accepted, parsed, and then passed out via notification, proxy, block, and so on. In the onSocket:didReadData:withTag: callback method, messages need to be read continuously because the server will return many times due to the large amount of data. So we need to define an MAX_BUFFER macro to indicate the maximum number of reads per session. When data length < We think it is possible to receive a complete message before parsing it.
Error handling
LGSocketServe.m
//
// LGSocketServe.m
// AsyncSocketDemo
//
#import "LGSocketServe.h"
@implementation LGSocketServe
static LGSocketServe *socketServe = nil;
#pragma mark public static methods
+ (LGSocketServe *)sharedSocketServe {
@synchronized(self) {
if(socketServe == nil) {
socketServe = [[[self class] alloc] init];
}
}
return socketServe;
}
+(id)allocWithZone:(NSZone *)zone
{
@synchronized(self)
{
if (socketServe == nil)
{
socketServe = [super allocWithZone:zone];
return socketServe;
}
}
return nil;
}
@end
0
An socket error will call back the onSocket:willDisconnectWithError: method to read the unread buffer via unreadData.
use
Import # import "LGSocketServe. h"
LGSocketServe *socketServe = [LGSocketServe sharedSocketServe];
//socket Disconnect the connection before you connect so you don't connect before socket The connection did not break causing a flit back
[socketServe cutOffSocket];
socketServe.socket.userData = SocketOfflineByServer;
[socketServe startConnectSocket];
// Send a message @"hello world" Just an example, depending on the message format on the server
[socketServe sendMessage:@"hello world"];