一:下载第三库 终端中import “CocoaAsyncSoket”
二:
服务器(.h)文件中让外部调用
//单列模式
+(MyChatServer*)sharedServer;
//开启聊天服务器
-(void)startServer;
//发送信息
-(void)sendMsg:(NSString*)msg;
服务器端(.m)文件中:
1.导入:#import <GCDAsyncSocket.h>
2.实现代理:@interface MyChatServer()
3.
//创建服务器socket
@property(nonatomic,strong)GCDAsyncSocket * serverSocket;
//创建全球队列
@property(nonatomic,strong)dispatch_queue_t golbalQueue;
//保存当前的客户端clientSocket
@property(nonatomic,strong)GCDAsyncSocket * clientSocket;
//创建心跳
@property(nonatomic,strong)CADisplayLink *link;
4.确保单例:
+(MyChatServer*)sharedServer{
if (instance == nil) {
instance = [[MyChatServer alloc]init];
//创建全局que
instance.golbalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建服务器的socket 注意这里的是初始化的同时已经制定了delegate
instance.serverSocket = [[GCDAsyncSocket alloc]initWithDelegate:instance delegateQueue:instance.golbalQueue];
}
return instance;
}
5.启动服务器:
//开启服务器
-(void)startServer{
//打开监听端口
NSError * err;
[_serverSocket acceptOnPort:12345 error:&err];
if (!err) {
NSLog(@"服务器开启成功");
}else{
NSLog(@"服务器开启失败");
}
}
6.发送信息
//发送信息 心跳
-(void)sendMsg: (NSString*)msg{
NSData *sendData = [msg dataUsingEncoding: NSUTF8StringEncoding];
[_clientSocket writeData:sendData withTimeout:-1 tag:100];
}
//发送心跳
-(void)heartBeat{
[self sendMsg:@""];
}
---------------实现代理-------------------
7.客户链接时调用这个代理
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
//sock为服务器的socket,服务器端的socket只负责客户端的链接,不负责数据的读取
//newSocket为客户端的socket
_clientSocket = newSocket;
//NSLog(@"客户端的socket %p 服务器端的socket %p",newSocket,sock);
//newSocket为客户端的socket,这里读取数据
[newSocket readDataWithTimeout:-1 tag:100];
//这也要心跳
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(heartBeat)];
_link.preferredFramesPerSecond = 1;
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
8.服务器写数据给客户端时调用
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
//[sock readDataWithTimeout:-1 tag:100];
[_clientSocket readDataWithTimeout:-1 tag:100];
}
9.接收客户发过来的数据时调用
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
//sock为客户端的socket
//NSLog(@"客户端的socket %p",sock);
//接收的数据
NSString * receiverStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (receiverStr.length == 0) {
NSLog(@"这是对方的心跳粘包%@",receiverStr);
}else{
//发送一个数据来了的消息
NSLog(@"他的消息%@",receiverStr);
[[NSNotificationCenter defaultCenter]postNotificationName:kOthertMessageDidComeNotify object:receiverStr];
}
}
///
二.服务器(.h)文件中让外部调用
+(MyChatClient*)sharedClient;
-(void)connectServer;
-(void)sendMsg: (NSString*)msg;
服务器.m实现文件
1.属性
//创建客户端socket
@property(nonatomic,strong)GCDAsyncSocket * socket;
//心跳
@property(nonatomic,strong)CADisplayLink *link;
//服务端
@property(nonatomic,strong)GCDAsyncSocket * serverSocket;
2.单例
+(MyChatClient*)sharedClient{
if (instance == nil) {
instance = [[MyChatClient alloc]init];
}
return instance;
}
3.链接服务器
- (void)connectServer{
//1.主机与端口号
NSString *host = @"192.168.43.85";
int port = 12345;
//初始化socket,这里有两种方式。分别为是主/子线程中运行socket。根据项目不同而定
_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];//这种是在主线程中运行
//_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 这种是在子线程中运行
//开始连接
NSError *error = nil;
[_socket connectToHost:host onPort:port error:&error];
if(error) {
NSLog(@"error:%@", error);
}
}
4.发送信息和心跳
//发送聊天数据
-(void)sendMsg: (NSString*)msg{
NSData *sendData = [msg dataUsingEncoding: NSUTF8StringEncoding];
[_socket writeData:sendData withTimeout:-1 tag:201];
[_serverSocket readDataWithTimeout:-1 tag:100];
}
//发送心跳
-(void)sendHeart{
//发送心跳
[self sendMsg:@""];
}
实现代理
5.与服务器链接成功时调用
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
//保存这个服务器端的socket
_serverSocket = sock;
//链接成功
NSLog(@"链接成功");
//发送心跳
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(sendHeart)];
_link.preferredFramesPerSecond = 0.1;
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
6.链接断开时调用
//断开链接
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
if (err) {
NSLog(@"链接失败");
}else{
NSLog(@"正常断开");
}
}
7.数据发送成功时调用
//数据发送成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
//发送完数据手动读取
[sock readDataWithTimeout:-1 tag:tag];
}
8.读取到服务器发过来的数据
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
//代理在子线程/主线程中使用
NSString * receiveStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (receiveStr.length == 0) {
//这是n个@“”的粘包
}else{
//这是真正的数据
//发送一条得到数据的消息
[[NSNotificationCenter defaultCenter]postNotificationName:kOthertMessageDidComeNotify object:receiveStr];
}
}
四、备注:仿QQ微信聊天界面 用UITabelView 配个 Bmob云端即可即可实现。