准备工作:开启ChatSever服务 ——— python 文件名(终端输入: cd phthon文件路径)
first Step:
1、简单聊天室(socket):
*实现登陆功能:
http://192.168.1.1/login实现登陆的功能 ①username ②password 传递给服务器
socket:192.168.1.1:123456(端口号)
登陆指令:iam:zhangsan
2、实现发送聊天信息的功能
发送聊天数据指令:msg:******
second Step:
①连接实现:
iOS里实现socket的连接,使用C语言
1.与服务器通过三次握手建立连接:
- (void)connectToServer:(id)sender {
NSString *host = @"127.0.0.1";
int port = 12345;
//全局队列
//创建一个socket对象
GCDAsyncSocket *socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIOROTY_DEFAULT, 0)];
//主队列
GCDAsyncSocket *socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
//连接
NSError *error = nil;
[socket connectToHost:host onPort:port error:&error];
if (error) {
NSLog(@"%@", error);
}
}
2.定义输入输出流
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
3.分配输入输出流的内存空间
CFStreamCreatePairWithSocketToHost(NULL, (_bridge CFStringRef)host, port(端口号), &readStream, &writeStream);
4.把C语言的输入输出流转成OC对象
在外面写大括号里的
{
NSInputStream *_inputStream;
NSOutputStream *_outStream;
}
_inputStream = (_bridge NSInputStream *)readStream;
_outStream = (_bridge NSOutStream *)writeStream;
5.设置代理, 监听数据接收的状态(NSStreamDelegate):
_outputStream.delegate = self;
_inputStream.delegate = self;
把输入输出流添加到主运行循环(主运行循环是监听网络状态的)
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefauleRunLoopMode];
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefauleRunLoopMode];
6.打开输入输出流
[_inputStream open];
[_outputStream open];
7.实现代理协议
- (void)Stream:(NSStream *)aStream handeleEvent:(NSStreamEvent)eventCode{
swith (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"成功连接建立,形成输入输出流的传输通道”);
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"有数据可读”);
[self readData];
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可以发送数据"):
break;
case NSStreamEventErrorOccurred:
NSLog(@"有错误发生,连接失败");
break;
case NSStreamEventEndEncountered:
NSLog(@"正常的断开连接");
//把输入输出流关闭, 并且从主运行循环中移除
[_inputStream close];
[_outputStream close];
[_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
break;
default:
breeak;
}
}
登陆
- (void)loginClick:(id)sender {
发送登陆请求,输出流(给数据的)
//接登陆的指令 iam:zhangsan
NSString *loginStr = @"iam:zhangsan";
//self sendDataToHost:loginStr];
//②:使用AsyncSocket
//-1代表 不设置超时
[_socket writeData:[loginStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:101];
}
读取服务器返回的数据
- (void)readData {
//定义缓冲区 (只能存储1024字节)
uint8_t buf[1024];
//读取数据
//len为服务器读取到的实际字节数
NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
//把缓冲区的实际字节数转成字符串
NSString *receiveStr = [[NSString alloc] initWithBytes:buf lenght:len encoding:NSUTF8StringEncoding];
NSLog(@"%@", receiveStr);
//把数据源添加进数组中
[self.msgs addObject:receiveStr];
[self.tableView reloadData];
}
Third Step:
首先绘制聊天界面(把底部输入栏的约束拖过来:bottomContraint), 之后在control中编写键盘监听:
[[NSNotificationCenter defaultCenter] addObserver: self selecter:@selector(kbWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self selecter:@selector(kbWillHide:) name:UIKeyboardWillHideNotification object:nil];
②:实现监听方法
键盘将要显示:
- (void)kbWillShow:(NSNotification *)noti {
//显示的时候将要改变bottomContraint
//获取键盘高度
CGFloat kbHeight = [noti.userInfo[UIKeyboardFrameEndUserInfoKey]CGRectVaule].size.height;
self.botttomConstraint.constant = kbHeight;
}
//设置信息显示的tableView的代理, 控制键盘的消失
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
reurn self.msgs.count;
}
- (UITableViewCell *)tableView:(UITabelView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:@"ChatCell"];
//显示信息
cell.textLable.text = self.msgs[indexPath.row];
}
//将要开始拖动的时候,如果键盘显示就回收
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
//隐藏键盘
[self.view endEditing:YES];
}
键盘将要消失:
- (void)kbWillHide:(NSNotification *)noti {
}
//把监听移除
- (void)dealloc {
[NSNotifiactionCenter dafaultCenter] removeObserver:self];
}
//实现信息的发送(UITextFieldDelegate):
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
//发送信息
//1.有数据发送
NSString *txt = textField.text;
if (txt.length == 0) {
return YES;
}
NSString *msg = [@"msg:" stringByAppendingString:txt];
[self sendDataToHost:msg];
return YES;
}
//发送数据
- (void)sendDataToHost:(NSString *)str {
//uint8_t * 代表字符数组
// NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
//[_outputStream write:data.bytes maxLength:data.length];
//②:
[_socket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:102];
}
fourth Step:实现聊天信息的展示
①:定义一个数组(msgs),存储信息
实现asyncSocket(添加文件GCDAsyncSocket): 在建立连接的时候添加异步
遵循socketDelegate协议,
①:连接成功的代理方法
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(@"%s", __func__);
}
②:断开连接的代理方法
- (void)socketDidDiscommect:(GCDAsyncSocket *)sock withError:(NSError *
err {
if(err) {
NSLog(@"连接失败“);
}else {
NSLog(@"正常断开”);
}
}
④:数据发送成功
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
//发送完数据手动读取
[sock readDataWithTimeout:-1 tag:tag];
}
③:读取数据 (在子线程调用的, 因为是全局队列,刷新有延迟; 如果是在主队列中,就会立即显示)
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *receiveStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (tag == 101) {//登陆tag
} else if (tag == 102) {//聊天数据
[sefl.msgs addObject:receiverStr];
//刷新表格
[self.tabelView reloadData];
}
}
网友评论