iOS Socket深入剖析
来源:互联网 发布:印度 人口 知乎 编辑:程序博客网 时间:2024/05/21 22:37
1.定义:
Socket是网络服务提供的一种套接字,通信两端都是Socket,网络通信通过Socket进行IO直接的传输,是一种长连接,让应用程序可以进行异步模式,提高速率,需要数据的时候才进行数据接收。
2.既然要了解Socket,就要对传输协议有一定的了解,可以把socket理解为封装TCP/IP协议API,TCP协议属于可靠性传输协议,需要进行三次握手(客户端发送信息到服务器,服务器响应发送到客户端,客户端响应后发送到服务器) UDP协议属于不可靠协议,是因为他不需要进行响应,就像知道一个大概的位置,然后就传送过去,每次能传64K左右的东西,传输速度很快,但是有时会丢包的情况。 所以视频,或则QQ群聊会用到UDP协议,QQ在单人聊天的时候,应该是进行TCP协议,所以个人认为QQ采用的是混合模型。
3.网络通信的三大要素:IP地址,传输协议,端口号。
IP地址:设备的唯一标示符。
传输协议:TCP UDP等
端口号:1-1023都是系统自带,如果个人要用的话需要1024以后的。需要熟记几个端口号,80,25,21等这里就不一一叙述。
4.开始进行代码
iOS主要按照NSStream(流)来发送和接收数据,可以设置流的代理,对流的状态变化做出相应连接建立,设置网络连接,绑定到主机和端口号,设置输入输出代理,监听数据流的状态,将输入输出添加至运行循环,打开输入输出流。
发送消息给服务器,有可读取字节时,读取服务器返回的内容,到达流末尾时,关闭流,同时并从主运行循环中删除。
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"完成");
break;
case NSStreamEventHasBytesAvailable:
NSLog(@"字节可读");
[self readData];
break;
case NSStreamEventHasSpaceAvailable:
NSLog(@"可发送字节");
break;
case NSStreamEventErrorOccurred:
NSLog(@"连接错误");
break;
case NSStreamEventEndEncountered:
NSLog(@"断开连接");
[self closeConnect];
break;
default:
NSLog(@"异常错误");
break;
}
}
- (void)closeConnect{
//1.输入输出流
[_inputStream close];
[_outputStream close];
//跳出运行循环
[_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void)readData{
//1.简历一个字节数组用于存放读取数据,大小为1024
uint8_t buf[1024];
//返回一个真实的数据大小
NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
if (len > 0) {
NSData *data = [NSData dataWithBytes:buf length:len];
NSString *dataString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
[_dataArray addObject:dataString];
[self.tableView reloadData];
}
}
- (IBAction)login:(id)sender {
//iam:定义的用户名协议
NSString *userName = @"iam:Snowwing";
NSData *data = [userName dataUsingEncoding:NSUTF8StringEncoding];
[_outputStream write:data.bytes maxLength:data.length];
}
- (IBAction)connect:(id)sender {
//主机IP地址
NSString *host = @"127.0.0.1";
//端口号
int port = 12345;
//读写数据流 要转换成OC
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
//绑定到主机和端口
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
//将C语言输入输出流转换成OC
_inputStream = (__bridge NSInputStream *)(readStream);
_outputStream = (__bridge NSOutputStream *)(writeStream);
//设置代理
_inputStream.delegate = self;
_outputStream.delegate = self;
//将输入输出流添加至循环
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
//打开输入输出流
[_outputStream open];
[_inputStream open];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
NSString *tftext = textField.text;
NSString *msg = [NSString stringWithFormat:@"msg:%@",tftext];
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[_outputStream write:data.bytes maxLength:data.length];
textField.text = nil;
return YES;
}
这里的服务器是调用第三方的服务器接口进行描述的
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
if(![_clientSockets containsObject:newSocket]){
[_clientSockets addObject:newSocket];
NSLog(@"%@链接主机成功",newSocket);
[newSocket readDataWithTimeout:-1 tag:0];
}
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
//获得接受字符
NSString *recverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//对字符串尾部回车做处理
while ([recverStr hasSuffix:@"\n"] || [recverStr hasSuffix:@"\r"]) {
recverStr = [recverStr substringToIndex:recverStr.length - 2];
}
NSUInteger index = [_clientSockets indexOfObject:sock];
NSString *key = [NSString stringWithFormat:@"%lu",index];
if ([recverStr hasPrefix:@"iam:"] && _clientNames[key] == nil) {
recverStr = [recverStr componentsSeparatedByString:@":"][1];
//将名字设为key以便找到对应socket进行单聊
[_clientNames setObject:key forKey:recverStr];
//存入名字方便以后消息发送时查找名字
_clientNames[key] = [recverStr stringByAppendingString:@":"];
recverStr = [recverStr stringByAppendingString:@" has join!"];
for (GCDAsyncSocket *client in self.clientSockets) {
[client writeData:[recverStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}
}else if([recverStr hasPrefix:@"msg:"]){
NSString *name = _clientNames[key];
recverStr = [recverStr componentsSeparatedByString:@":"][1];
if ([recverStr hasPrefix:@"/to "]) {
NSString *toName = [recverStr componentsSeparatedByString:@" "][1];
recverStr = [recverStr componentsSeparatedByString:@" "][2];
recverStr = [name stringByAppendingString:recverStr];
if (_clientNames[toName]) {
GCDAsyncSocket *socket = [_clientSockets objectAtIndex:[_clientNames[toName] integerValue]];
[socket writeData:[recverStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}
}else {
recverStr = [name stringByAppendingString:recverStr];
for (GCDAsyncSocket *client in self.clientSockets) {
[client writeData:[recverStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}
}
}else if ([recverStr isEqualToString:@"quit"]) {
//断开连接
[sock setDelegate:nil];
[sock disconnect];
[_clientNames removeObjectForKey:key];
[_clientSockets removeObject:sock];
}
[sock readDataWithTimeout:-1 tag:0];
}
- iOS Socket深入剖析
- 深入剖析Socket实现
- 深入剖析Socket实现
- Socket深入剖析
- 深入剖析Socket实现
- 深入剖析Socket实现
- iOS Runtime深入剖析
- 深入剖析 iOS 性能优化
- 深入剖析 iOS 性能优化
- 深入剖析 iOS 性能优化
- 深入剖析 iOS 性能优化
- 深入剖析 iOS 编译 Clang / LLVM
- IOS 深入剖析 bounds 和 frame
- 深入剖析 iOS 编译 Clang / LLVM
- 深入剖析 iOS 编译 Clang / LLVM
- 【深入剖析Linux协议栈】socket connect 发起连接请求
- Socket剖析
- 【Java TCP/IP Socket】深入剖析socket——数据传输的底层实现
- HDOJ 1517A Multiplication Game(巴士博弈)
- 61. Rotate List
- sqlplus中break命令的使用
- php的学习笔记之面向对象(二)
- onAttachedToWindow () 和 onDetachedFromWindow ()
- iOS Socket深入剖析
- Java 中的相等性和一致性
- MongoDB configuration
- Java中equals和==的区别
- 最短路
- Vim实战指南(八):Vim vs vi
- storm 文档(3)----入门指导
- GitHub Android Librarys Top 100 简介
- 如何安装Yaf框架?