Bonjour写的聊天室的思路(一)——搭建服务器
来源:互联网 发布:te网络配线架打法图解 编辑:程序博客网 时间:2024/06/08 05:21
搭建服务器:
1.创建socket--CFSocketCreate设置accept后callback + 确保相同的socket在每次连接后得到重用(setsockopt())
2.bind——创建sockaddr_in struct记录服务器信息,port设为0(主机自动分配)再用[NSData dataWithBytes: length: ]转换为NSData,用CFSocketSetAddressData进行连接,其他的连接方式还有直接bind(CFSocketNativeHandle, struct sockaddr * ,sizeof(struct sockeaddr ))
3.找出主机为你分配的port,就是反过来从与sockadd_in struct连接的socket得到address,得到的是NSData类型,通过memcpy转化为struct sockaddr_in,然后就得到port了。
NSData *socketAddressActualData = [(NSData *)CFSocketCopyAddress(listeningSocket) autorelease]; // Convert socket data into a usable structure struct sockaddr_in socketAddressActual; memcpy(&socketAddressActual, [socketAddressActualData bytes], [socketAddressActualData length]); self.port = ntohs(socketAddressActual.sin_port);
4.socket加入runloop进行监听
CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, listeningSocket, 0); CFRunLoopAddSource(currentRunLoop, runLoopSource, kCFRunLoopCommonModes); CFRelease(runLoopSource);
Publish Bonjour Service
1.初始化NSNetservice
NSString* chatRoomName = [NSString stringWithFormat:@"%@'s chat room", [[AppConfig sharedInstance] name]]; // create new instance of netService self.netService = [[NSNetService alloc] initWithDomain:@"" type:@"_chatty._tcp." name:chatRoomName port:self.port];
2.加入主线程
[self.netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
3.设置代理,连接失败关闭server
[self.netService setDelegate:self];
- (void) netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict{ if ( sender != self.netService ) { return; } // Stop socket server [self terminateServer]; // Stop Bonjour [self unpublishService]; // Let delegate know about failure [delegate serverFailed:self reason:@"Failed to publish service via Bonjour (duplicate server name?)"];}
- (void) terminateServer{ if ( listeningSocket != nil ) { CFSocketInvalidate(listeningSocket);CFRelease(listeningSocket);listeningSocket = nil; }}
- (void) unpublishService{ if ( self.netService ) {[self.netService stop];[self.netService removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];self.netService = nil;}}
4.publish
[self.netService publish];
CFSocket的callback:
1.使用socket进行connect
2.设置代理,handleNewConnection:
static void serverAcceptCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info){ // We can only process "connection accepted" calls here if ( type != kCFSocketAcceptCallBack ) { return; } // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data; Server *server = (Server *)info; [server handleNewNativeSocket:nativeSocketHandle];}
- (void) handleNewNativeSocket:(CFSocketNativeHandle)nativeSocketHandle{ Connection* connection = [[[Connection alloc] initWithNativeSocketHandle:nativeSocketHandle] autorelease]; // In case of errors, close native socket handle if ( connection == nil ) { close(nativeSocketHandle); return; } // finish connecting BOOL succeed = [connection connect]; if ( !succeed ) { [connection close]; return; } // Pass this on to our delegate [delegate handleNewConnection:connection];}
Connect的过程
1.通过之前的socket创建readStream和writeStream
CFStreamCreatePairWithSocket(kCFAllocatorDefault, self.connectedSocketHandle, &readStream, &writeStream);
2.然后对incomingDataBuffer和outgoingDataBuffer进行初始化,
incomingDataBuffer = [[NSMutableData alloc] init]; outgoingDataBuffer = [[NSMutableData alloc] init];
3.设置readstream和writestream随着socket的关闭而关闭,
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
4.再设置readstream和writestream的callback,
CFOptionFlags registeredEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventCanAcceptBytes | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred; // Setup stream context - reference to 'self' will be passed to stream event handling callbacks CFStreamClientContext ctx = {0, self, NULL, NULL, NULL}; // Specify callbacks that will be handling stream events CFReadStreamSetClient(readStream, registeredEvents, readStreamEventHandler, &ctx); CFWriteStreamSetClient(writeStream, registeredEvents, writeStreamEventHandler, &ctx);
5.将readstream和write stream加入runloop
CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
6.测试下readStream和writeStream能不能打开
if ( !CFReadStreamOpen(readStream) || !CFWriteStreamOpen(writeStream)) { [self close]; return NO; }
7.close就是将readStream、writeStream、incomingBuffer、outgoingBuffer清空。readStream和writeStream关闭的方式:踢出runloop,再read/writeStream close然后release,然后设置位NULL
ReadStream的回调
1.incomingbuffer的长度设置位readstream的长度
2.去除incomingDataBuffer中头部长度sizeof(int)
3.将下一段sizeof(int)包装成NSDictionary用delegate传出。
WriteStream的回调
1.outgoingDataBuffer的长度不为0且CFWriteStreamCanAcceptBytes
2.向writeStream中写入:CFWriteStreamWrite(writeStream, [outgoingDataBuffer bytes], [outgoingDataBuffer length])
3.移除outgoingBuffer中已经写入的字节
- Bonjour写的聊天室的思路(一)——搭建服务器
- Bonjour写的聊天室的思路(二)——UI和logic
- Bonjour聊天室的总体思路
- Bonjour (苹果电脑公司的服务器搜索协议)
- 实现聊天室的思路整理
- 基于netty的网络聊天室(一)——基础框架搭建
- 基于netty的网络聊天室(一)——基础框架搭建
- 面向新手的Web服务器搭建(一)——IIS的搭建
- 面向新手的Web服务器搭建(一)——IIS的搭建
- Linux下C语言项目—聊天室的搭建1.0
- 聊天室项目(二)界面的搭建
- 基于Linux的聊天室(服务器)初成版
- 实现聊天室的思路 和部分代码
- 简易版的聊天室实现思路
- svn服务器的搭建详解(一)
- LINUX SENDMAIL服务器的搭建 (一)
- WAMP服务器的搭建(一)
- 聊天室 搭建服务器
- 20150625_OC之XML格式解析
- 适配器(Adapter)设计模式和接口实现完全解耦
- 转载 -- C#抽象方法及其学习方法
- Ubuntu下vim中ctags的配置方法
- OC基础6:多态、动态类型和动态绑定
- Bonjour写的聊天室的思路(一)——搭建服务器
- Telnet协议,SSH协议(安全外壳协议),SSL协议(安全套接层协议),HTTPS(Hypertext Transfer Protocol Secure)安全超文本传输协议
- vi技巧(1)
- 网站底部版权信息正确书写方式
- 【love2d】Hello love2d!
- 常见协议及其默认端口号
- p->num,与p.num的区别
- 设计模式-适配器模式
- gfg