Socket(套接字)
* Socket就是为网络服务提供的一种机制
* 通信的两端都是Socket
* 网络通信其实就是Socket间的通信
* 数据在两个Socket间通过IO传输
我们来看看下面这张图:
如上图所示:假设客户端要向服务端发送消息,并且服务器会回应客户端。那么步骤是这样的:
1. 必须先将带有IP+端口等数据发送给服务器,在与服务器完成三次握手后建立连接。
2.如果建立连接成功,会出现2条传输通道,两端分别有个输出流和一个输入流。一旦连接建立成功,两端便会实时地监控各自的输入流。
3.因为是长连接,所以连接一直存在,直至任何一方主动断开连接!
拓展:
关于长连接与短连接
*一般选择长连接或者短连接由我们的需求决定,上面举的是即时通信的例子,所以选择长连接。因为如果中途一方断开,连接便失效,数据也将没有运输通道。(暂且这样理解,后面会详细讲解)
*而平时我们常常用到得HTTP就是短连接,因为客户端只需向服务器请求一次,服务器也只需根据客户端请求的数据进行相应地回应,便不再实时交流,所以服务器在成功返回数据后便会主动断开与客户端的连接。客户端如果需要进行请求,便需要建立新的连接。
接下来简单地实现一下聊天功能
在DEMO里面已经放了个预先准备好的数据库,可以直接使用。使用方法:打开终端 —— 打开文件路径(cd ../../../)—— 打开文件(python chat.py)出现chat server success!字样表示启动成功。
然后新建项目,连接数据库,这里需要用到C语言的代码,然后再将C语言转换成OC对象
//1.建立一个连接
NSString*host = @"127.0.0.1";
intport = 33333;
CFReadStreamRefreadStream; //输入流
CFWriteStreamRefwriteStream; //输出流
CFStreamCreatePairWithSocketToHost(NULL,(__bridgeCFStringRef)host,port, &readStream, &writeStream);
// 将C语言输入输出流转换成OC对象
_inputStream= (__bridgeNSInputStream*)(readStream);
_outputStream= (__bridgeNSOutputStream*)(writeStream);
// 设置代理
_inputStream.delegate=self;
_outputStream.delegate=self;
//把输入输出流添加到主运行循环
//不添加的话代理可能不被调用
[_inputStreamscheduleInRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];
[_outputStreamscheduleInRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];
// 打开输入输出流
[_inputStream open];
[_outputStream open];
实现
NSStream代理方法
- (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)eventCode
{
NSLog(@"%@",aStream);
// NSStreamEventOpenCompleted = 1UL << 0, 流打开成功
// NSStreamEventHasBytesAvailable = 1UL << 1, 有字节可读
// NSStreamEventHasSpaceAvailable = 1UL << 2, 可以发送字节
// NSStreamEventErrorOccurred = 1UL << 3, 连接出错
// NSStreamEventEndEncountered = 1UL << 4 连接结束
switch(eventCode) {
caseNSStreamEventOpenCompleted:
NSLog(@"流打开成功");
break;
caseNSStreamEventHasBytesAvailable:
NSLog(@"有字节可读");
[selfreadData];
break;
caseNSStreamEventHasSpaceAvailable:
NSLog(@"可以发送字节");
break;
caseNSStreamEventErrorOccurred:
NSLog(@"连接出错");
break;
caseNSStreamEventEndEncountered:
NSLog(@"连接结束");
//关闭输入输出流
[_inputStreamclose];
[_outputStreamclose];
//从主运行循环移除
[_inputStreamremoveFromRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];
[_outputStreamremoveFromRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];
break;
default:
break;
}
}
既然是聊天,首先就需要登录,还需要一个UITextField
输入框,这边就不验证密码,直接用用户名登录
- (void)login
{
// 2.聊天
// 2.1登录
// 发送用户名
// 登录指令
NSString*loginStr = @"iam:zhangsan";
// 把Str转成NSData
NSData*data= [loginStr dataUsingEncoding:NSUTF8StringEncoding];
[_outputStreamwrite:data.bytesmaxLength:data.length];
}
登陆成功后读取服务器返回的数据
#pragma mark 读了服务器返回的数据
-(void)readData{
//建立一个缓冲区可以放1024个字节
uint8_tbuf[1024];
// 返回实际装的字节数
NSIntegerlen = [_inputStreamread:bufmaxLength:sizeof(buf)];
//把字节数组转化成字符串
NSData*data = [NSDatadataWithBytes:buflength:len];
// 从服务器接收到的数据
NSString*recStr= [[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];
NSLog(@"gdgdfgdf%@",recStr);
[selfreloadDataWithText:recStr];
}
实现输入框代理
-(BOOL)textFieldShouldReturn:(UITextField*)textField{
NSString*text = textField.text;
NSLog(@"%@",text);
// 聊天信息
NSString*msgStr = [NSStringstringWithFormat:@"msg:%@",text];
//把Str转成NSData
NSData*data= [msgStr dataUsingEncoding:NSUTF8StringEncoding];
// 刷新表格
[selfreloadDataWithText:msgStr];
// 发送数据
[_outputStreamwrite:data.bytesmaxLength:data.length];
// 发送完数据,清空textField
textField.text= nil;
return YES;
}
因为刷新等部分代码很多地方会用到,所以抽出来放到一个方法内方便调用
-(void)reloadDataWithText:(NSString*)text{
[self.chatMsgsaddObject:text];
[self.tableViewreloadData];
// 数据多,应该往上滚动
NSIndexPath*lastPath = [NSIndexPathindexPathForRow:self.chatMsgs.count- 1inSection:0];
[self.tableViewscrollToRowAtIndexPath:lastPathatScrollPosition:UITableViewScrollPositionBottomanimated:YES];
}
最后就是完成Tableview的数据集
#pragma mark 表格的数据源
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{
return self.chatMsgs.count;
}
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
staticNSString*ID = @"Cell";
UITableViewCell*cell= [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text= self.chatMsgs[indexPath.row];
return cell;
}
运行效果如下:
Socket的概念和简单使用就先到这里了,需要DEMO的可以到下面链接下载:
链接: http://pan.baidu.com/s/1mgITR7M 密码: q916
如果有错误或者有什么问题可以联系我,转载请注明出处,谢谢!