iOS从零开始学习socket编程——HTTP1.0服务器端
2015-04-19 18:40
417 查看
在前一篇文章《iOS从零开始学习socket编程——HTTP1.0客户端》中已经简单的介绍过了Socket编程和一些基本原理。并且实现了简单的iOS客户端(原文地址:/article/1477419.html)
这里再简单介绍一下如何使用OC搭建socket的服务器端。虽然这并不是一个好的解决方案,通常我们使用Java或者PHP抑或NodeJS来搭建服务器后台。但是还是有必要了解一下OC的做法,顺便加深对Socket编程的理解。
废话不多说,还是导入AsyncSocket.h和AsyncSocket.m文件。这里我们创建的是一个桌面端的软件(iOS端也可。),创建了一个AppController类。
下面直接上代码,有点长,会慢慢解释。原来的程序是有图形界面的,不过为了更好地解释socket的工作原理,这里就把不必要的
AppController.h文件非常简单,有一个AsyncSocket类的socket对象,还有一个用来存放已连接的socket的数组。isRunning表示是否在运行,三个IBOutlet是界面需要的。fileName用于读取http请求的文件名,还有一个动作事件,在启动/结束键被按下时触发。
因为Storyboard文件无法上传,所以以上代码只能显示Socket服务器的工作流程而不能直接复制运行。需要自己写出图形界面或者绑定端口号。
关于didReadData方法使用时遇到的问题和解决方法以及详细分析,参见另一篇文章——《AsyncSocket didReadData函数详解》
地址:/article/1477420.html
这里再简单介绍一下如何使用OC搭建socket的服务器端。虽然这并不是一个好的解决方案,通常我们使用Java或者PHP抑或NodeJS来搭建服务器后台。但是还是有必要了解一下OC的做法,顺便加深对Socket编程的理解。
废话不多说,还是导入AsyncSocket.h和AsyncSocket.m文件。这里我们创建的是一个桌面端的软件(iOS端也可。),创建了一个AppController类。
下面直接上代码,有点长,会慢慢解释。原来的程序是有图形界面的,不过为了更好地解释socket的工作原理,这里就把不必要的
//AppController.h #import <Cocoa/Cocoa.h> #import "AsyncSocket.h" @interface AppController : NSObject<AsyncSocketDelegate> { AsyncSocket *listenSocket; NSMutableArray *connectedSockets; BOOL isRunning; IBOutlet id logView; IBOutlet id portField; IBOutlet id startStopButton; } @property (atomic,strong) NSString *fileName; @property (atomic,strong) NSMutableData *receiveData; - (IBAction)startStop:(id)sender; @end
AppController.h文件非常简单,有一个AsyncSocket类的socket对象,还有一个用来存放已连接的socket的数组。isRunning表示是否在运行,三个IBOutlet是界面需要的。fileName用于读取http请求的文件名,还有一个动作事件,在启动/结束键被按下时触发。
#import "AppController.h" #import "AsyncSocket.h" #import <AppKit/AppKit.h> #define WELCOME_MSG 0 #define ECHO_MSG 1 #define WARNING_MSG 2 #define READ_TIMEOUT 15.0 #define READ_TIMEOUT_EXTENSION 10.0 #define FORMAT(format, ...) [NSString stringWithFormat:(format), ##__VA_ARGS__] @interface AppController (PrivateAPI) @end @implementation AppController @synthesize fileName; - (id)init { if((self = [super init])) { listenSocket = [[AsyncSocket alloc] initWithDelegate:self]; connectedSockets = [[NSMutableArray alloc] initWithCapacity:1]; isRunning = NO; } return self; } - (void)awakeFromNib { [logView setString:@""]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [listenSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; } - (IBAction)startStop:(id)sender { if(!isRunning) { int port = [portField intValue]; if(port < 0 || port > 65535) { port = 0; } NSError *error = nil; if(![listenSocket acceptOnPort:port error:&error]) { return; } isRunning = YES; [portField setEnabled:NO]; [startStopButton setTitle:@"Stop"]; } else { // Stop accepting connections [listenSocket disconnect]; // Stop any client connections NSUInteger i; for(i = 0; i < [connectedSockets count]; i++) { [[connectedSockets objectAtIndex:i] disconnect]; } isRunning = false; [portField setEnabled:YES]; [startStopButton setTitle:@"Start"]; } } - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket { [connectedSockets addObject:newSocket]; } - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { [sock readDataWithTimeout:-1 tag:0];//very important NSString *welcomeMsg = @"Welcome to the AsyncSocket Echo Server\r\n"; NSData *welcomeData = [welcomeMsg dataUsingEncoding:NSUTF8StringEncoding]; [sock readDataToData:[AsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0]; } - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { if(tag == ECHO_MSG) { [sock readDataToData:[AsyncSocket CRLFData] withTimeout:READ_TIMEOUT tag:0]; } } - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding]; NSRange endRange = [msg rangeOfString:@"HTTP"]; NSRange beginRange = [msg rangeOfString:@"/"]; if (beginRange.location != NSNotFound && endRange.location != NSNotFound) { NSRange fileRange = NSMakeRange(beginRange.location, endRange.location - beginRange.location-1); fileName = [msg substringWithRange:fileRange]; if(fileName && ![fileName isEqualToString:@""]){ NSData *returnData = [self getResponseHeader:fileName]; [sock writeData:returnData withTimeout:-1 tag:ECHO_MSG]; fileName = nil; [sock disconnectAfterWriting]; } else{ [sock writeData:data withTimeout:-1 tag:ECHO_MSG]; fileName = nil; [sock disconnectAfterWriting]; } } else{ NSLog(@"Header not found"); dispatch_async(dispatch_get_main_queue(), ^{ [sock writeData:data withTimeout:-1 tag:ECHO_MSG]; fileName = nil; [sock disconnectAfterWriting]; }); } } /** * This method is called if a read has timed out. * It allows us to optionally extend the timeout. * We use this method to issue a warning to the user prior to disconnecting them. **/ - (NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length { if(elapsed <= READ_TIMEOUT) { NSString *warningMsg = @"Are you still there?\r\n"; NSData *warningData = [warningMsg dataUsingEncoding:NSUTF8StringEncoding]; [sock writeData:warningData withTimeout:-1 tag:WARNING_MSG]; return READ_TIMEOUT_EXTENSION; } return 0.0; } - (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err { [self logInfo:FORMAT(@"Client Disconnected: %@:%hu", [sock connectedHost], [sock connectedPort])]; } - (void)onSocketDidDisconnect:(AsyncSocket *)sock { [connectedSockets removeObject:sock]; } - (NSData *)getResponseHeader:(NSString *)localFileName{ //获取Response Header NSMutableString *header = [[NSMutableString alloc]init]; NSMutableData *returnData = [[NSMutableData alloc]init]; NSData *fileContent = [NSData dataWithContentsOfFile:localFileName]; int contentLength = (int)[fileContent length]; [header appendString:@"HTTP/1.0 200 OK\r\n"]; [header appendString:@"Connection: close\r\n"]; [header appendString:@"Server: Apache/1.3.0(Unix)\r\n"]; NSString *contentLengthString = [NSString stringWithFormat:@"Content-Length:%d\r\n",contentLength]; [header appendString:contentLengthString]; NSString *mimeString = [NSString stringWithFormat:@"Content-Type: %@\r\n",[self getMimeByFileName:localFileName]]; [header appendString:mimeString]; [header appendString:@"\r\n"]; NSData *headerData = [header dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"header = %@",header); [returnData appendData:headerData]; [returnData appendData:fileContent]; //NSLog(@"return data = %@",returnData); return (NSData *)returnData; } - (NSString *)getMimeByFileName:(NSString *)localFileName{ //通过文件名判断Response Header的MIME类型 NSRange htmlRange = [localFileName rangeOfString:@"html"]; NSRange htmRange = [localFileName rangeOfString:@"htm"]; NSRange pngRange = [localFileName rangeOfString:@"png"]; if (htmlRange.location != NSNotFound || htmRange.location != NSNotFound) { NSString *mime = [[NSString alloc]initWithFormat:@"text/html"]; return mime; } else if(pngRange.location != NSNotFound){ NSString *mime = [[NSString alloc]initWithFormat:@"image/png"]; return mime; } NSString *mime = [[NSString alloc]initWithFormat:@"unknown"]; return mime; } @end
因为Storyboard文件无法上传,所以以上代码只能显示Socket服务器的工作流程而不能直接复制运行。需要自己写出图形界面或者绑定端口号。
关于didReadData方法使用时遇到的问题和解决方法以及详细分析,参见另一篇文章——《AsyncSocket didReadData函数详解》
地址:/article/1477420.html
相关文章推荐
- iOS从零开始学习socket编程——HTTP1.0客户端
- iOS从零开始学习socket编程——高并发多线程服务器
- ios socket编程的客户端和服务器端通信简单实例
- Android基础学习之Socket、Http、Json网络编程
- ios网络编程(http、socket)
- IOS学习笔记之 Socket 编程
- iOS中的Socket编程,socket,http,https基础知识(二)
- 从零开始学习iOS开发-股票记帐本1.0(1)
- ios网络编程(http、socket)
- ios网络编程(http、socket)
- iOS游戏开始者从零开始:6个月的学习编程经历
- ios网络编程(http、socket)
- 从零开始学习iOS开发-股票记帐本1.0(2)
- 从零开始学习iOS开发-股票记帐本1.0(3)
- iOS 各种网络编程总结--进程、线程、Socket、HTTP、TCP/IP、TCP和UDP
- 从零开始学习iOS开发-股票记帐本1.0(4)
- ios网络编程(http、socket)
- Android编程学习:http + socket 通信例程
- IOS学习之[深入浅出Cocoa]iOS网络编程之Socket
- ios网络编程(http、socket)