从Samples中入门IOS开发(五)------ 基于HTTP的网络编程

AFNetworking3.1.0源码分析(八)AFHTTPRequestSerializer 之AFStreamingMultipartFormData下 本章接着上章继续讲解AFStreamingMultipartFormData设置上传文件(文本,图像,视频)时对请求的设置。 1:首先说下在iOS网络请求中以POST/PUT形式发送请求是,设置请求体的两种形式:HTTPBody 和 HTTPBodyStream HTTPBody:适用于普通的post/put请求(大部分接口请求都使用这种)因为发送的请求体占用的内存很少。 HTTPBodyS 阅读详情

上一篇讲的是如何通过socket进行网络传输,实际上对于互联网上的资源,我们更多的是基于http来开发,SimpleURLConnections展示了如何基于http来进行数据传输,这里主要是讲client如何向http服务器请求和传输数据,http服务器端的实现不在此例子范围之内,实际上就是普通的http服务器。

从本例中主要能学到三点:

  • 基于Get下载文件
  • 基于Put上传文件
  • 基于Post上传文件
基于Get下载文件

首先通过URL打开Connection:

    request = [NSURLRequest requestWithURL:url];
    assert(request != nil);
    
    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
    assert(self.connection != nil);

然后实现NSURLConnectionDelegate来处理数据传输,其中实现下载图片到本地文件的方法如下:

- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
    // A delegate method called by the NSURLConnection as data arrives.  We just 
    // write the data to the file.
{
    #pragma unused(theConnection)
    NSInteger       dataLength;
    const uint8_t * dataBytes;
    NSInteger       bytesWritten;
    NSInteger       bytesWrittenSoFar;

    assert(theConnection == self.connection);
    
    dataLength = [data length];
    dataBytes  = [data bytes];

    bytesWrittenSoFar = 0;
    do {
        bytesWritten = [self.fileStream write:&dataBytes[bytesWrittenSoFar] maxLength:dataLength - bytesWrittenSoFar];
        assert(bytesWritten != 0);
        if (bytesWritten == -1) {
            [self stopReceiveWithStatus:@"File write error"];
            break;
        } else {
            bytesWrittenSoFar += bytesWritten;
        }
    } while (bytesWrittenSoFar != dataLength);
}

基于Put上传文件

Put和Get类似,只不过文件上传是通过设置HTTP header来完成的:

self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];
assert(self.fileStream != nil);

// Open a connection for the URL, configured to PUT the file.

request = [NSMutableURLRequest requestWithURL:url];
assert(request != nil);

[request setHTTPMethod:@"PUT"];
[request setHTTPBodyStream:self.fileStream];

if ( [filePath.pathExtension isEqual:@"png"] ) {
    [request setValue:@"image/png" forHTTPHeaderField:@"Content-Type"];
} else if ( [filePath.pathExtension isEqual:@"jpg"] ) {
    [request setValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
} else if ( [filePath.pathExtension isEqual:@"gif"] ) {
    [request setValue:@"image/gif" forHTTPHeaderField:@"Content-Type"];
} else {
    assert(NO);
}

contentLength = (NSNumber *) [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] objectForKey:NSFileSize];
assert( [contentLength isKindOfClass:[NSNumber class]] );
[request setValue:[contentLength description] forHTTPHeaderField:@"Content-Length"];

self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

其中最主要的是设置三个header属性:method, body和contentLength
[request setHTTPMethod : @"PUT" ];
[request setHTTPBodyStream: self. fileStream];
[request setValue :[contentLength description ] forHTTPHeaderField : @"Content-Length" ];

基于Post上传文件

基于Post上传文件与Put最大不同点是,http body里除了放入文件本身的数据流之外,还得在文件数据流前后放入结构性的描述信息,比如之前:

bodyPrefixStr = [NSString stringWithFormat:
            @
            // empty preamble
            "\r\n"
            "--%@\r\n"
            "Content-Disposition: form-data; name=\"fileContents\"; filename=\"%@\"\r\n"
            "Content-Type: %@\r\n"
            "\r\n"

之后:

bodySuffixStr = [NSString stringWithFormat:
            @
            "\r\n"
            "--%@\r\n"
            "Content-Disposition: form-data; name=\"uploadButton\"\r\n"
            "\r\n"
            "Upload File\r\n"
            "--%@--\r\n" 
            "\r\n"
            //empty epilogue
            ,
            boundaryStr, 
            boundaryStr
        ];

因此,这里就需要能够把这些数据加入到文件流中,本例采用的方案是生产者和消费者的模式,把这两段信息拼接到文件流中:

[NSStream createBoundInputStream:&consStream outputStream:&prodStream bufferSize:32768];
assert(consStream != nil);
assert(prodStream != nil);
self.consumerStream = consStream;
self.producerStream = prodStream;

self.producerStream.delegate = self;
[self.producerStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.producerStream open];

// Set up our state to send the body prefix first.

self.buffer      = [self.bodyPrefixData bytes];
self.bufferLimit = [self.bodyPrefixData length];

// Open a connection for the URL, configured to POST the file.

request = [NSMutableURLRequest requestWithURL:url];
assert(request != nil);

[request setHTTPMethod:@"POST"];
[request setHTTPBodyStream:self.consumerStream];

[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=\"%@\"", boundaryStr] forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%llu", bodyLength] forHTTPHeaderField:@"Content-Length"];

self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

然后在handleevent中处理数据流的拼接:

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
    // An NSStream delegate callback that's called when events happen on our 
    // network stream.
{
    #pragma unused(aStream)
    assert(aStream == self.producerStream);

    switch (eventCode) {
        case NSStreamEventOpenCompleted: {
            // NSLog(@"producer stream opened");
        } break;
        case NSStreamEventHasBytesAvailable: {
            assert(NO);     // should never happen for the output stream
        } break;
        case NSStreamEventHasSpaceAvailable: {
            // Check to see if we've run off the end of our buffer.  If we have, 
            // work out the next buffer of data to send.
            
            if (self.bufferOffset == self.bufferLimit) {

                // See if we're transitioning from the prefix to the file data.
                // If so, allocate a file buffer.
                
                if (self.bodyPrefixData != nil) {
                    self.bodyPrefixData = nil;

                    assert(self.bufferOnHeap == NULL);
                    self.bufferOnHeap = malloc(kPostBufferSize);
                    assert(self.bufferOnHeap != NULL);
                    self.buffer = self.bufferOnHeap;
                    
                    self.bufferOffset = 0;
                    self.bufferLimit  = 0;
                }
                
                // If we still have file data to send, read the next chunk. 
                
                if (self.fileStream != nil) {
                    NSInteger   bytesRead;
                    
                    bytesRead = [self.fileStream read:self.bufferOnHeap maxLength:kPostBufferSize];
                    
                    if (bytesRead == -1) {
                        [self stopSendWithStatus:@"File read error"];
                    } else if (bytesRead != 0) {
                        self.bufferOffset = 0;
                        self.bufferLimit  = bytesRead;
                    } else {
                        // If we hit the end of the file, transition to sending the 
                        // suffix.

                        [self.fileStream close];
                        self.fileStream = nil;
                        
                        assert(self.bufferOnHeap != NULL);
                        free(self.bufferOnHeap);
                        self.bufferOnHeap = NULL;
                        self.buffer       = [self.bodySuffixData bytes];

                        self.bufferOffset = 0;
                        self.bufferLimit  = [self.bodySuffixData length];
                    }
                }
                
                if ( (self.bufferOffset == self.bufferLimit) && (self.producerStream != nil) ) {
                    self.producerStream.delegate = nil;
                    [self.producerStream close];
                }
            }
            
            // Send the next chunk of data in our buffer.
            
            if (self.bufferOffset != self.bufferLimit) {
                NSInteger   bytesWritten;
                bytesWritten = [self.producerStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
                if (bytesWritten <= 0) {
                    [self stopSendWithStatus:@"Network write error"];
                } else {
                    self.bufferOffset += bytesWritten;
                }
            }
        } break;
        case NSStreamEventErrorOccurred: {
            NSLog(@"producer stream error %@", [aStream streamError]);
            [self stopSendWithStatus:@"Stream open error"];
        } break;
        case NSStreamEventEndEncountered: {
            assert(NO);     // should never happen for the output stream
        } break;
        default: {
            assert(NO);
        } break;
    }
}

基于Post的数据传输看上去很复杂,实际上道理还是很简单,重点就在于数据流的拼接上。

Unity集成Qwen3-ASR-1.7B:构建高精度离线语音交互系统 语音识别(ASR)技术是实现自然语言交互的核心,其原理是将音频信号转换为文本。在游戏开发、智能助手等应用场景中,本地化、低延迟的语音识别方案具有重要技术价值,它能有效解决云端API的网络依赖、延迟和成本问题。通过客户端-服务器架构,将计算密集的模型推理部署在服务器端,客户端负责音频采集与传输,是实现高性能语音交互的常见工程实践。本文以Unity游戏引擎为例,详细阐述了如何集成支持52种语言的Qwen3-ASR-1.7B开源大模型,并利用vLLM推理后端和WebSocket通信协议,构建一套高精度、可离线的实 阅读详情

相关推荐

漏洞修复: Web服务器限制只允许通过GET/POST请求

http请求中的8种请求方法 1、opions 返回服务器针对特定资源所支持的HTML请求方法 或web服务器发送测试服务器功能(允许客户端查看服务器性能) 2、Get 向特定资源发出请求(请求指定页面信息,并返回实体主体) 3、Post 向指定资源提交数据进行处理请求(提交表单、上传文件),又可能导致新的资源的建立或原有资源的修改 4、Put 向指定资源位置上上传其最新内容(从客户端向服务器传送的数据取代指定文档的内容) 5、Head 与服务器索与get请求一致的相应,响应体不会返回,获取包含在小消息头

Bertram的博客 2583

iOS -读书笔记-网络请求

知道“3次握手”吗?突然想起这个词什么是3次握手? TCP三次握手/四次挥手详解 这里是3次握手的详细解释 3次握手就是为了可靠的传送数据,TCP(什么是TCP呢?TCP就是一种可靠传输的协议)在发送数据之前,两台主机之间进行3次握手。3次握手完成后才发送数据。预备知识: 位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) P

雪松-不仅仅是程序员 1058

IOS stream模拟http请求获取数据

ios 有三个demo 1.NSURL 下载网络图片(block和delegate两种方式) 2.NSURLSession 下载网络图片,请求json数据(自己封装的网络block) 3.利用 NSstream 来模拟http请求获取数据

iOS 将请求参数放入body 进行网络请求

项目需要在网络请求的时候把相关参数包在body里面,由于之前这类操作遇到的较少,所以在这儿做下记录,具体代码如下: NSString *dicTojson = @"字典转字符串的参数"; NSString *url = [NSString stringWithFormat:@"%@VMS2Service.cgi?Cmd=%@",baseUrl, method]; NSData *body = [dicTojson dataUsingEncoding:NSUTF8StringEncoding] ..

ForeverMyheart的博客 3091

最新测算源码PHP算命源码-风水八字-八字起名-塔罗牌占卜

未来,随着技术的发展和用户需求的变化,我们可以继续对系统进行升级和优化,以满足更多用户的需求和期望。数据库设计:创建一个名为bazi的数据库表,包含以下字段:id(自增ID)、name(姓名)、sex(性别)、birth_date(出生日期)、birth_time(出生时间)、bazi(八字结果)。数据库设计:创建一个包含塔罗牌信息的数据库表,如tarot_cards,包含字段:id(塔罗牌ID)、name(塔罗牌名称)、meaning(塔罗牌含义)等。根据操作系统的不同,PHP的安装方法会有所不同。

shanbeizi的博客 2417

《深入浅出强化学习原理入门》学习笔记(三)机器人找金币应用实例

《深入浅出强化学习原理入门》学习笔记(三)MDP应用实例

lxs3213196的博客 3186

HTTP请求:iOS网络功能——从iOS应用中发出HTTP请求

高层iOS HTTP API iOS有3个主要的方法可以执行HTTP请求和接收响应:同步、队列式异步、异步。 所有请求类型共用的对象 所有的URL加载请求方法会共用几个对象:NSURL、NSURLRequest、NSURLConnection、NSURLResponse。 1、NSURL 可以指向文件资源,也可以指向网络资源。 NSURL *url = [NSURL URLWithString:mysteryString]; NSData *data = [NSData dataWithCon

run_in_road的博客 1609

android OTA升级之后,apk崩溃无法启动

也就是说,我们这个高低版本是fingerprint相同的情况,这个问题追述到jenkins编译,启动job时会初始化一个BUILD_NUMBER值,这个值正好跟Android的build系统的名称重复,这就导致Android build系统那一套拼接时间戳的值不会走,因为jenkins一启动就会定义该值,而我们jenkins服务器迁移过,这个值又会从1开始累计,导致前后版本都是16,从而导致fingerprint一致。问题背景:系统版本从低版本升级到高版本后,apk崩溃启动失败。硬件平台:QCS6125。

kevin's cache的专栏 1342

Http 用Stream传输

一般文件传输用Stream, Stream的创建有两种方式,

小小幸 8342

MT4-EA自动化交易研究笔记(2022-04-22)

自从接触到mt4的EA自动化交易,更让我这个10多年的老程序员看到了曙光,目前来看也确实出了一点成果,只是是否能稳定盈利有待时间的考验,所以开此专栏,一来做做记录与分析,更好的优化我的EA,二来也希望能与更多的高手交流,以完善我的交易系统

t35254056的博客 2290

FDTD材料nk值拟合优化指南:利用材料资源管理器提升光学模型精度

本文详细介绍了如何利用FDTD仿真软件中的材料资源管理器,对材料nk值进行精确拟合与优化,从而提升光学模型的仿真精度。文章通过实战案例,解析了拟合参数调整、报告解读以及针对varFDTD求解器的特殊注意事项,帮助用户从根本上解决仿真结果不准的常见问题。

weixin_29196891的博客 352

Ember.js Glimmer 嵌入 API 实战:在自定义宿主中集成多个全局组件

本文基于 Ember.js 仓库的 [internal-docs/guides/embedding/05-components.md](https://link.gitcode.com/i/30a5a90303f67253d2865adb9d37856d) 文档,讲解如何在 Glimmer 的 AOT 嵌入环境中从"单一组件 + 若干 helper"升级为"多组件"的完整宿主集成方案。你将掌握 `

gitblog_00328的博客 436

立体仓库WCS控制系统-AGV通信代码

string str = "任务下发,WCS->NT8000(q-Message),ikey:" + p.ikey.ToString() + "fromStation:" + p.fromStation.ToString() + "toStation:" + p.toStation.ToString();if (nt8000.Connect(_ServerAddr, _ServerPort)) QueueSpeech.AddQueue(string.Format("与NT8000重连成功"));

xdpcxq的专栏 2201

CocoaHTTPServer:如何在Apple生态系统中构建高效嵌入式HTTP服务器

在当今移动应用和桌面软件开发中,开发者经常面临一个关键挑战:如何在应用程序内部无缝集成HTTP服务功能,而无需依赖外部服务器或复杂的网络架构。无论是为iOS应用提供文档无线访问、为Mac桌面应用构建通信后端,还是为服务器应用实现远程监控,嵌入式HTTP服务器都成为了一个迫切的技术需求。 CocoaHTTPServer正是为这一场景而生的轻量级解决方案。作为一个专门为Mac OS X和iOS平台设

gitblog_01084的博客 279

uniapp | 基于高德地图实现位置选择功能(安卓端)

在uni-app项目中实现地图位置选择功能的解决方案。由于uni.chooseLocation功能受限,采用高德地图API自主开发。系统由父组件poiMap.vue(负责展示和跳转)和子组件poiBox.vue(核心地图逻辑)构成,通过父子组件通信传递位置数据。关键技术包括:1)使用AMapLoader动态加载地图SDK;2)集成PositionPicker实现拖拽选点;3)异步加载AMapUI插件;4)通过事件监听获取位置详情(地址/经纬度)。

大胆尝试,小心实践 730

第02章:HSA-Runtime架构概览

摘要: 本章深入解析HSA Runtime的三层架构设计,包括公共API层(C语言接口)、核心实现层(C++业务逻辑)和驱动抽象层(硬件交互)。重点介绍了Runtime的核心组件(Agent、Queue、Signal、Memory)及其关系,以及初始化流程、配置选项和调试功能。通过学习,读者将掌握HSA Runtime的整体架构,为后续模块学习奠定基础。

图形/计算GPU的驱动与虚拟化技术分享园地 2915

Unity AR工业数据可视化实战:Nano-Banana Studio集成与性能优化

在工业物联网与增强现实(AR)应用开发中,实时数据可视化是连接物理设备与数字孪生的核心技术。其原理在于将来自传感器、PLC等多源异构的实时数据流,通过高效的通信协议与数据绑定机制,驱动虚拟场景中的UI、模型与特效,从而实现设备状态的透明化监控与交互。这项技术的核心价值在于极大提升了远程维护、操作培训等场景的效率和安全性。面对工业级应用对数据高频、低延迟、高保真的严苛要求,传统开发方式往往陷入网络编程与数据处理的复杂性泥潭。本文以Unity AR Foundation为开发平台,深入探讨如何利用Nano-Ba

weixin_30719711的博客 356

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

AFNetworking2.0源码解析<二>

续AFNetworking2.0源码解析 本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization。 AFURLRequestSerialization用于帮助构建NSURLRequest,主要做了两个事情: 1.构建普通请求:格式化请求参数,生成HTTP Header。 2.构建multipart请求。 分别看看它在这两点具

sunyazhou13的专栏 613

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

iOS如何使用Stream进行抓包

iOS如何使用Stream进行抓包

weixin_66818294的博客 7171

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

iOS抓包工具——Stream

Stream是一款在iOS端的网络抓包工具,该工具可以直接独立运行在iOS设备,无需依赖PC环境。Stream面向对象为广大前端开发、客户端开发、后端开发、运维工程师、测试工程师以及具备一定网络分析能力的普通用户。

小司机的奥拓 5981

iOS文件上传注意事项

文件上传注意事项(文件上传用的都是POST请求) 一、步骤: 1.创建URL 2.创建NSMutableURLRequest 3.设置HTTPMethod为POST形式 4.设置请求头Content-Type为”multipart/form-data” 5.把要上传的数据追加到HTTPBody(要注意大文件或小文件等) 6.创建一个http连接 二、数据上传步骤中需要注

X-Prince的博客 1372

iOS大文件上传服务器,iOS如何通过流式传输将大型资产文件上传到服务器

假设您的数据太大而无法放入内存:一种有效且可靠的方法将利用一对有界CFStream(见CFStreamCreateBoundPair).有界流对的输入流设置为NSMutableURLRequest的HTTPBodyStream属性.有界流对的输出流将用于写入从固定大小的内存缓冲区获得的字节,该缓冲区已填充ALAssetRepresentation的getBytes:fromOffset:lengt...

weixin_26850069的博客 656

安卓Packet Capture抓包教程(未完)/ios抓包工具stream抓包教程

ios抓包工具stream抓包教程

qq_42785182的博客 5万+

ios Http living Stream详解三

Deploying HTTP Live Streaming (原文地址) https://developer.apple.com/library/ios/#documentation/networkinginternet/conceptual/streamingmediaguide/Introduction/Introduction.html  为了发布我们的 HTTP

jidiao的专栏 1540
上一篇: 从Samples中入门IOS开发(四)------ 基于socket的网络编程
下一篇: 从Samples中入门IOS开发(六)------ Photo和Album浏览
cutesource
博客等级 码龄17年 5041粉丝 151原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值