前几天,公司有一个长连接的需求。需要在移动端搭建一个服务器,一边后台可以给推送消息。通过从网上查找资料,终于现在弄出一套自己的服务,包括客户端。
首先我是使用CAsyncSocket类来搭建的。我们可以用pod,也可已用手托。它都是在CocoaAsyncSocket库下。pod的方法pod 'CocoaAsyncSocket’
,手动拖得我是从GCD里面拖得。
首先是服务端
@interface MyViewController ()<GCDAsyncSocketDelegate>
//开启服务按钮,主要是为效果展示而用
@property (weak, nonatomic) IBOutlet UIButton *button;
// 服务器socket
@property (nonatomic, strong) GCDAsyncSocket *serverSocket;
// 为客户端生成的socket
@property (nonatomic, strong) GCDAsyncSocket *clientSocket;
@end
因为是用xib拖拽的按钮,所以在此按钮的点击事件开启服务功能
- (IBAction)clickButton:(id)sender { // 1. 创建服务器socket self.serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; // 2. 开放端口 NSError *error = nil; BOOL result = [self.serverSocket acceptOnPort:30000 error:&error]; // 3. 判断端口号是否开放成功 if (result) { NSLog(@"端口开放成功"); } else { NSLog(@"端口开放失败"); } }
服务端实现我们所用类的代理方法了
#pragma mark - GCDAsyncSocketDelegate
//当客户端链接服务器端的socket, 为客户端单生成一个socket
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{ NSLog(@"链接成功"); //IP: newSocket.connectedHost //端口号: newSocket.connectedPort NSLog(@"链接地址:%@", newSocket.connectedHost); NSLog(@"端口号:%hu", newSocket.connectedPort); // 存储新的端口号 self.clientSocket = newSocket; //读取客户端发过来的消息 [self.clientSocket readDataWithTimeout:-1 tag:0]; }
// 服务端接收到消息
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",message); }
好了,这样就可以实现简单开启服务了。里面还有好多的代理方法,我现在是没实现。
接下来是客户端
@interface MyViewController ()<GCDAsyncSocketDelegate> //连接服务时调用按钮 @property (weak, nonatomic) IBOutlet UIButton *linkServer; //发送消息是调用按钮 @property (weak, nonatomic) IBOutlet UIButton *sendMessage; //socket @property (nonatomic, strong) GCDAsyncSocket *socket; @end
//按钮的点击事件,连接服务器
- (IBAction)clickButton:(id)sender { // 1. 创建socket self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; // 2. 与服务器的socket链接起来 NSError *error = nil; BOOL result = [self.socket connectToHost:@"192.168.1.59" onPort:30000 error:&error]; // 3. 判断链接是否成功 if (result) { NSLog(@"客户端链接服务器成功"); } else { NSLog(@"客户端链接服务器失败"); } }
- (IBAction)clickButtonWithSendMessage:(id)sender { NSData *data = [@"我是刘文江" dataUsingEncoding:NSUTF8StringEncoding]; [self.socket writeData:data withTimeout:-1 tag:0]; //这个地方是个单例 ,这样可以保证我们的socket不销毁 JQSocket *socket = [JQSocket defaultSocket]; [socket.mySocket readDataWithTimeout:-1 tag:0]; }
客户端实现我们所用类的代理方法了
// 客户端链接服务器端成功, 客户端获取地址和端口号
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"链接服务器%@", host); JQSocket *socket = [JQSocket defaultSocket]; socket.mySocket = self.socket; }
// 客户端已经获取到内容
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",content); }
下面去给大家上个效果图
大家看到了“我是AAAAAA”这条消息就是客户端发过来的。