iOS 实现简单的Http 服务
http 是计算机之间通讯协议的比较简单的一种。在iPhone上,由于没有同步数据和文件共享,所以实现PC与设备之间的数据传输的最佳方式就是在程序中嵌套一个http 服务器。在这篇帖子中,我将简单的演示第三方的http 服务器的使用。
示例程序运行如下(在PC端输入设备的IP和端口,便可选取当前PC的文件进行上传至当前的设备)

该服务器涉及的相关类如下图所示


代码实现,创建一个自己需求的HttpConnection类继承于第三方的HttpConnection,代码如下
MyHTTPConnection.h
#import "HTTPConnection.h"
@class MultipartFormDataParser;
@interface MyHTTPConnection : HTTPConnection
{
MultipartFormDataParser * parser;
NSFileHandle * storeFile;
NSMutableArray * uploadedFiles;
}
@end
MyHTTPConnection.m
#import "MyHTTPConnection.h"
#import "HTTPMessage.h"
#import "HTTPDataResponse.h"
#import "DDNumber.h"
#import "HTTPLogging.h"
#import "MultipartFormDataParser.h"
#import "MultipartMessageHeaderField.h"
#import "HTTPDynamicFileResponse.h"
#import "HTTPFileResponse.h"
static const int httpLogLevel = HTTP_LOG_LEVEL_VERBOSE;
@interface MyHTTPConnection ()
{
float totalSize;
float progress;
}
@end
@implementation MyHTTPConnection
个人需要,1-8的方法都有实现
1:- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
{
NSLog(@"%s",__FUNCTION__);
HTTPLogTrace();
if ( [ method isEqualToString:@"POST"] ) {
if ( [path isEqualToString:@"/upload.html"] ) {
return YES;
}
}
return [super supportsMethod:method atPath:path];
}
2:-(BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path{
if([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.html"]) {
// here we need to make sure, boundary is set in header
NSString* contentType = [request headerField:@"Content-Type"];
NSUInteger paramsSeparator = [contentType rangeOfString:@";"].location;
if( NSNotFound == paramsSeparator ) {
return NO;
}
if( paramsSeparator >= contentType.length - 1 ) {
return NO;
}
NSString* type = [contentType substringToIndex:paramsSeparator];
if( ![type isEqualToString:@"multipart/form-data"] ) {
// we expect multipart/form-data content type
return NO;
}
// enumerate all params in content-type, and find boundary there
NSArray* params = [[contentType substringFromIndex:paramsSeparator + 1] componentsSeparatedByString:@";"];
for( NSString* param in params ) {
paramsSeparator = [param rangeOfString:@"="].location;
if( (NSNotFound == paramsSeparator) || paramsSeparator >= param.length - 1 ) {
continue;
}
NSString* paramName = [param substringWithRange:NSMakeRange(1, paramsSeparator-1)];
NSString* paramValue = [param substringFromIndex:paramsSeparator+1];
if( [paramName isEqualToString: @"boundary"] ) {
// let's separate the boundary from content-type, to make it more handy to handle
[request setHeaderField:@"boundary" value:paramValue];
}
}
// check if boundary specified
if( nil == [request headerField:@"boundary"] ) {
return NO;
}
return YES;
}
return [super expectsRequestBodyFromMethod:method atPath:path];
}
3:- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path{
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.html"])
{
// this method will generate response with links to uploaded file
NSMutableString* filesStr = [[NSMutableString alloc] init];
for( NSString* filePath in uploadedFiles ) {
//generate links
[filesStr appendFormat:@"%@<br/><br/>", [filePath lastPathComponent]];
}
NSString* templatePath = [[config documentRoot] stringByAppendingPathComponent:@"upload.html"];
NSDictionary* replacementDict = [NSDictionary dictionaryWithObject:filesStr forKey:@"MyFiles"];
// use dynamic file response to apply our links to response template
return [[HTTPDynamicFileResponse alloc] initWithFilePath:templatePath forConnection:self separator:@"%" replacementDictionary:replacementDict];
}
if( [method isEqualToString:@"GET"] && [path hasPrefix:@"/upload/"] ) {
// let download the uploaded files
return [[HTTPFileResponse alloc] initWithFilePath: [[config documentRoot] stringByAppendingString:path] forConnection:self];
}
return [super httpResponseForMethod:method URI:path];
}
4:- (void)prepareForBodyWithSize:(UInt64)contentLength{
HTTPLogTrace();
totalSize = contentLength/1000.0/1000.0;
NSLog(@"%f",contentLength/1000.0/1000.0);
// set up mime parser
NSString* boundary = [request headerField:@"boundary"];
parser = [[MultipartFormDataParser alloc] initWithBoundary:boundary formEncoding:NSUTF8StringEncoding];
parser.delegate = self;
uploadedFiles = [[NSMutableArray alloc] init];
}
5:- (void)processBodyData:(NSData *)postDataChunk{
HTTPLogTrace();
progress += postDataChunk.length/1024.0/1024.0;
NSLog(@"%f",progress);
NSString * temp = [ NSString stringWithFormat:@"上传进度:%.2fMB/%.2fMB",progress,totalSize ];
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD showProgress:progress/totalSize status:temp maskType:SVProgressHUDMaskTypeBlack];
});
// append data to the parser. It will invoke callbacks to let us handle
// parsed data.
[parser appendData:postDataChunk];
}
6:- (void) processStartOfPartWithHeader:(MultipartMessageHeader*) header{
NSLog(@"%s",__FUNCTION__);
MultipartMessageHeaderField* disposition = [header.fields objectForKey:@"Content-Disposition"];
NSString* filename = [[disposition.params objectForKey:@"filename"] lastPathComponent];
NSLog(@"####filename=%@",filename);
if ( (nil == filename) || [filename isEqualToString: @""] ) {
// it's either not a file part, or
// an empty form sent. we won't handle it.
return;
}
NSString* uploadDirPath = [self CreatreTempDir] ;
// NSLog(@"uploadDirPath%@",[self CreatDir]);
BOOL isDir = YES;
if (![[NSFileManager defaultManager]fileExistsAtPath:uploadDirPath isDirectory:&isDir ]) {
[[NSFileManager defaultManager]createDirectoryAtPath:uploadDirPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString * filePath = [uploadDirPath stringByAppendingPathComponent:filename];
NSFileManager * fileManager = [NSFileManager defaultManager];
if( [[NSFileManager defaultManager] fileExistsAtPath:filePath] ) {
storeFile = nil;
}
else {
HTTPLogVerbose(@"Saving file to %@", filePath);
NSError *error;
if(![[NSFileManager defaultManager] createDirectoryAtPath:uploadDirPath withIntermediateDirectories:true attributes:nil error:&error]) {
HTTPLogError(@"Could not create directory at path: %@----%@", filePath,error);
}
if(![[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]) {
HTTPLogError(@"Could not create file at path: %@", filePath);
}
storeFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
[uploadedFiles addObject: [NSString stringWithFormat:@"/upload/%@", filename]];
}
}
7:- (void) processContent:(NSData*) data WithHeader:(MultipartMessageHeader*) header{
if(!storeFile)
{
MultipartMessageHeaderField* disposition = [header.fields objectForKey:@"Content-Disposition"];
NSString* filename = [[disposition.params objectForKey:@"filename"] lastPathComponent];
NSLog(@"####filename=%@",filename);
if ( (nil == filename) || [filename isEqualToString: @""] ) {
// it's either not a file part, or
// an empty form sent. we won't handle it.
return;
}
NSString* uploadDirPath = [self CreatreTempDir] ;
NSString * filePath = [uploadDirPath stringByAppendingPathComponent:filename];
storeFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
[uploadedFiles addObject: [NSString stringWithFormat:@"/upload/%@", filename]];
}
if( storeFile ) {
[storeFile writeData:data];
}
}
8:- (void) processEndOfPartWithHeader:(MultipartMessageHeader*) header{
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
progress = 0.f;
MultipartMessageHeaderField* disposition = [header.fields objectForKey:@"Content-Disposition"];
NSString* filename = [[disposition.params objectForKey:@"filename"] lastPathComponent] ;
// NSLog(@"####END ---filename=%@",filename);
NSString * tempFilePath = [[ self CreatreTempDir ] stringByAppendingPathComponent:filename];
NSMutableArray *arraynumber = [NSMutableArray arrayWithContentsOfFile:[Global getChangePathName]];
NSString *strnumber = [arraynumber lastObject];
NSString * uploadFilePath = [[ self CreatDir ] stringByAppendingPathComponent: [[NSString stringWithFormat:@"%d.",[strnumber intValue] + 1 ] stringByAppendingString:filename]];
[arraynumber addObject:[NSString stringWithFormat:@"%d", [strnumber intValue] + 1]];
[arraynumber writeToFile:[Global getChangePathName] atomically:YES];
BOOL result = [ self copyMissFile:tempFilePath toPath:uploadFilePath ];
if (result) {
NSLog(@"移动成功");
}else{
NSLog(@"移动失败");
}
[storeFile closeFile];
storeFile = nil;
}
- (BOOL)copyMissFile:(NSString * )sourcePath toPath:(NSString *)toPath{
BOOL retVal ;
NSLog(@"%s",__FUNCTION__);
// if ( [fileManger fileExistsAtPath:toPath] ) {
// [fileManger removeItemAtPath:toPath error:nil];
// }
retVal = [[ NSFileManager defaultManager ] moveItemAtPath:sourcePath toPath:toPath error:nil];
return retVal;
}
下面两个方法都是创建文件,大家自己可以随意定义
-(NSString *)CreatDir;
-(NSString *)CreatreTempDir;
下面根据需求实现以下这些方法,我是在全局的类里面实现的
Global.m
+ (BOOL)createiPhoneServer //创建并设置iPhone的服务器
{
Global * global = [ Global sharedGlobal ];
global.httpServer = [[HTTPServer alloc] init];
[global.httpServer setType:@"_http._tcp."];
NSString *docRoot = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"MyResources"] stringByAppendingPathComponent:@"Web"];
BOOL isDir = YES ;
if ( [[NSFileManager defaultManager] fileExistsAtPath:docRoot isDirectory:&isDir ] ) {
NSLog(@"找到Web文件夹");
}
[global.httpServer setDocumentRoot:docRoot];
[global.httpServer setPort:Http_Port];//本地端口
[global.httpServer setConnectionClass:[MyHTTPConnection class]];//设置连接类为我们之前代码实现的连接类
return YES;
}
//开启服务器
+ (BOOL)startServer
{
Global * global = [ Global sharedGlobal];
NSError * error;
if ( [global.httpServer start:&error] ) {
NSLog(@"开启成功%u",[global.httpServer listeningPort]);
return YES;
}else
{
NSLog(@"开启失败,%@",error);
return NO;
}
}
+ (BOOL)stopServer
{
[[Global sharedGlobal].httpServer stop:YES];
return YES;
}
//获得当前设备的IP
+(NSString *)getIPAddress
{
NSString *address = @"开启失败";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0) {
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL) {
if(temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
NSString * str = nil;
if ( [address isEqualToString:@"开启失败"] ) {
str = @"开启失败";
}else {
str = [NSString stringWithFormat:@"http://%@:%d",address, Http_Port ];
}
return str;
}
//获取当前设备的网络状态
+(NSString *) getDeviceSSID
{
NSArray *ifs = (__bridge id)CNCopySupportedInterfaces() ;
id info = nil;
for (NSString *ifnam in ifs) {
info = (__bridge id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
if (info && [info count]) {
break;
}
}
NSDictionary *dctySSID = (NSDictionary *)info;
NSString *ssid = [ dctySSID objectForKey:@"SSID" ];
ssid = ssid== nil?@"无网络":ssid;
return ssid;
}
然后再你需要的地方开启这个服务即可,至此http 服务搭建完成,开启服务之后就可在PC的浏览器输入当前的设备IP地址和端口,如http://192.168.2.155:8088,然后上传所需的文件即可,根据程序设计,这些文件会存在相应的地方
iOS 实现简单的Http 服务的更多相关文章
- iOS开发 简单实现视频音频的边下边播 (转)
1.ios视频音频边缓存边播放,缓存时可以在已下载的部分拖拽进度条. 3.无论是下载到一半退出还是下载完退出,已缓存的数据都存到自己指定的一个路径.如果已下载完,下次播放时可以不再走网络,直接播放 ...
- 通过HttpListener实现简单的Http服务
使用HttpListener实现简单的Http服务 HttpListener提供一个简单的.可通过编程方式控制的 HTTP 协议侦听器.使用它可以很容易的提供一些Http服务,而无需启动IIS这类大型 ...
- iOS上简单推送通知(Push Notification)的实现
iOS上简单推送通知(Push Notification)的实现 根据这篇很好的教程(http://www.raywenderlich.com/3443/apple-push-notification ...
- 树莓派(Raspberry Pi)搭建简单的lamp服务
树莓派(Raspberry Pi)搭建简单的lamp服务: 1. LAMP 的安装 sudo apt-get install apache2 mysql-server mysql-client php ...
- 构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介
构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介 熟悉将用于 Apache Tuscany SCA for C++ 的 API.您将通过本文了解该 API 的主要组 ...
- Netty4.0学习笔记系列之三:构建简单的http服务(转)
http://blog.csdn.net/u013252773/article/details/21254257 本文主要介绍如何通过Netty构建一个简单的http服务. 想要实现的目的是: 1.C ...
- 简单ESB的服务架构
简单ESB的服务架构 这几个月一直在修改架构,所以迟迟没有更新博客. 新的架构是一个基于简单esb的服务架构,主要构成是esb服务注册,wcf服务,MVC项目构成. 首先,我门来看一看解决方案, 1. ...
- 新项目架构从零开始(三)------基于简单ESB的服务架构
这几个月一直在修改架构,所以迟迟没有更新博客. 新的架构是一个基于简单esb的服务架构,主要构成是esb服务注册,wcf服务,MVC项目构成. 首先,我门来看一看解决方案, 1.Common 在Com ...
- 简单 TCP/IP 服务功能
本主题使用每台 Windows 计算机上提供的 Echo 和 Quote of the Day 服务.在所有 Windows 版本中都提供了简单 TCP/IP 服务功能.该功能会提供了以下服务:Cha ...
随机推荐
- 《Java程序设计》实验三 实验报告
实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2 ...
- 关于JVM的类型和模式
原文出处: 摆渡者 引言 曾几何时,我也敲打过无数次这样的命令: 然而之前的我都只关心过版本号,也就是第一行的内容.今天,我们就来看看第3行输出的内容:JVM的类型和工作模式. 其实说Server和C ...
- Permutations [LeetCode]
Given a collection of numbers, return all possible permutations. For example,[1,2,3] have the follow ...
- iOS开发 iOS10推送必看
iOS10更新之后,推送也是做了一些小小的修改,下面我就给大家仔细说说.希望看完我的这篇文章,对大家有所帮助. 一.简单入门篇---看完就可以简单适配完了 相对简单的推送证书以及环境的问题,我就不在这 ...
- Response返回JSON数据到前台页面
转自博文:<Response JSON数据返回>http://blog.csdn.net/anialy/article/details/8665471 简述: 在servlet填充Resp ...
- Android开发--TextView的应用
1.概述 TextView主要用于Activity中文本的应用.其中layout中xml文件(activity)设置文本的宽度,高度,ID:values中strings.xml设置文本内容. Text ...
- Java开发 Eclipse使用技巧(转)
1.如何设置默认的代码目录为src,默认的输出目录为bin? window->Preferences->java->Build Path中,右侧选择Folders就可以 2.如何为快 ...
- Maven 系列 一 :Maven 快速入门及简单使用【转】
开发环境 MyEclipse 2014 JDK 1.8 Maven 3.2.1 1.什么是Maven? Maven是一个项目管理工具,主要用于项目构建,依赖管理,项目信息管理. 2.下载及安装 下载最 ...
- 使用Camera进行拍照
Android应用提供了Camera来控制拍照,使用Camera进行拍照的步骤如下: 1.调用Camera的open()方法打开相机. 2.调用Camera的getParameters()方法获取拍照 ...
- Time, Clocks, and the Ordering of Events in a Distributed System
作者:Leslie Lamport(非常厉害的老头了) 在使用消息进行通信的分布式系统中,使用物理时钟对不同process进行时间同步与事件排序是非常困难的.一是因为不同process的时钟有差异,另 ...