好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

IOS网络编程:HTTP

IOS网络编程:HTTP

IOS网络编程:HTTP

HTTP定义了一种在服务器和客户端之间传递数据的途径。

URL定义了一种唯一标示资源在网络中位置的途径。

REQUESTS 和 RESPONSES:

客户端先建立一个TCP连接,然后发送一个请求。服务器受到请求处理后发送一个响应向客户端传递数据。然后客户端可以继续发送请求或者关闭这个TCP连接。

HTTPS:
在TCP连接建立后,发送请求之前,需要建立一个一个SSL会话。

request方法和它们的用途

iOS的NSURLRequest和它的子类NSMutableURLRequest提供了建立HTTP请求的方法。

NSURLResponse 和  它的子类 NSHTTPURLResponse 处理返回的数据。

URL:

 

Protocol包括HTTP、FTP和file。

URL编码:

NSString *urlString =  @"  http://myhost.com?query=This is a question  " ; 
NSString *encoded = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSURL用来管理URL。

 

IOS HTTP APIS:

涉及到下面一些类:

NSURL ,  NSURLRequest ,  NSURLConnection , 和  NSURLResponse .

1、 NSURL

NSURL可以定义本地文件和网络文件

NSURL *url = [NSURL urlWithString:@"http://www.google.com"]; 
NSData *data = [NSData dataWithContentsOfURL:url];

NSURL定义了很多访问器:

 if  (url.port == nil) { 
  NSLog( @" Port is nil " ); } else {   NSLog( @" Port is not nil " ); }

2、NSURLRequest

创建了NSURL后,就可以用NSURLRequest建立请求了:

NSURL *url = [NSURL URLWithString:  @"  https://gdata.youtube.com/feeds/api/standardfeeds/top_rated  "  ];
  if  (url ==  nil) {
     NSLog(  @"  Invalid URL  " ); 

   return ; } NSURLRequest *request = [NSURLRequest requestWithURL:url];

if (request == nil) {   NSLog( @" Invalid Request " ); return ; }

NSMutableURLRequest是 NSURLRequest 的子类,提供了改变请求的属性的方法:

NSURL *url = [NSURL urlWithString @"  http://server.com/postme  " ]; 
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod: @" POST " ]; [req setHTTPBody:[ @" Post body " dataUsingEncoding:NSUTF8StringEncoding]];

如果你要发送一个图片或者视频,那么用需要用NSInputStream,它没有把数据全部加在到内存。

NSMutableURLRequest *request =  [NSMutableURLRequest requestWithURL:url];
NSInputStream  *inStream =  [NSInputStream inputStreamWithFileAtPath:srcFilePath];
[request setHTTPBodyStream:inStream];
[request setHTTPMethod:  @"  POST  " ];

3、NSURLConnection

提供了初始化、开始、和取消一个连接。

4、 NSURLResponse

发送同步请求:

- (NSArray *) doSyncRequest:(NSString * )urlString {
      //   make the NSURL object from the string 
    NSURL *url =  [NSURL URLWithString:urlString];
    
      //   Create the request object with a 30 second timeout and a cache policy to always retrieve the
      //   feed regardless of cachability. 
    NSURLRequest *request =  
       [NSURLRequest requestWithURL:url 
                        cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData 
                    timeoutInterval:  30.0  ];
    
      //   Send the request and wait for a response 
    NSHTTPURLResponse   * response;
    NSError              * error;
    NSData  *data =  [NSURLConnection sendSynchronousRequest:request 
                                         returningResponse: & response 
                                                     error: & error];
      //   check for an error 
     if  (error !=  nil) {
        NSLog(  @"  Error on load = %@  "  , [error localizedDescription]);
          return   nil;
    }
    
      //   check the HTTP status 
     if  ([response isKindOfClass:[NSHTTPURLResponse  class  ]]) {
        NSHTTPURLResponse  *httpResponse = (NSHTTPURLResponse * )response;
          if  (httpResponse.statusCode !=  200  ) {
              return   nil;
        }
        NSLog(  @"  Headers: %@  "  , [httpResponse allHeaderFields]);
    }
    
      //   Parse the data returned into an NSDictionary 
    NSDictionary *dictionary =  
        [XMLReader dictionaryForXMLData:data 
                                  error: & error];
      //   Dump the dictionary to the log file 
    NSLog( @"  feed = %@  "  , dictionary);
    
    NSArray  *entries = [self getEntriesArray:dictionary];
    
      //   return the list if items from the feed. 
     return   entries;

} 

 

Queued Asynchronous Requests:

- ( void ) doQueuedRequest:(NSString *)urlString   delegate :( id ) delegate   {
      //   make the NSURL object 
    NSURL *url =  [NSURL URLWithString:urlString];
    
      //   create the request object with a no cache policy and a 30 second timeout. 
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval: 30.0  ];
    
      //   If the queue doesn't exist, create one. 
     if  (queue ==  nil) {
        queue  =  [[NSOperationQueue alloc] init];
    }
    
      //   send the request and specify the code to execute when the request completes or fails. 
     [NSURLConnection sendAsynchronousRequest:request 
                                       queue:queue 
                           completionHandler: ^(NSURLResponse * response, 
                                               NSData  * data, 
                                               NSError  * error) {
                               
              if  (error !=  nil) {
               NSLog(  @"  Error on load = %@  "  , [error localizedDescription]);
            }   else   {
                
                  //   check the HTTP status 
                 if  ([response isKindOfClass:[NSHTTPURLResponse  class  ]]) {
                    NSHTTPURLResponse  *httpResponse = (NSHTTPURLResponse * )response;
                      if  (httpResponse.statusCode !=  200  ) {
                          return  ;
                    }
                    NSLog(  @"  Headers: %@  "  , [httpResponse allHeaderFields]);
                }
                               
                  //   parse the results and make a dictionary 
                NSDictionary *dictionary =  
                   [XMLReader dictionaryForXMLData:data 
                                             error: & error];
                NSLog(  @"  feed = %@  "  , dictionary);

                  //   get the dictionary entries. 
                NSArray *entries = [self getEntriesArray:dictionary];

                  //   call the delegate 
                 if  ([ delegate   respondsToSelector:@selector(setVideos:)]) {
                    [  delegate   performSelectorOnMainThread:@selector(setVideos:) 
                                               withObject:entries 
                                            waitUntilDone:YES];
                }
            }
    }];
} 

Asynchronous Requests:

 #import  <Foundation/Foundation.h>

 #define  kDownloadComplete   @"downloadComplete"

 @class   DownloadProgressView;

  @interface  AsyncDownloader : NSObject <NSURLConnectionDelegate>  {
      //   The number of bytes that need to be downloaded 
     long   long     downloadSize;
      //   the total amount downloaded thus far 
     long   long     totalDownloaded;
}
  //   A reference to the progress view to show the user how things are progressing 
@property (assign) DownloadProgressView * progressView;
  //   The target MP4 file 
@property (strong) NSString * targetFile;
  //   The original URL to download.  Due to redirects the actual content may come from another URL 
@property (strong) NSString * srcURL;
  //   The open file to which the content is written 
@property (strong) NSFileHandle * outputHandle;
  //   The name of the temp file to which the content is streamed. This file is moved to the target file when
  //   the download is complete 
@property (strong) NSString * tempFile;
@property (strong) NSURLConnection  * conn;

  //   instructs the class to start the download. 
- ( void  ) start;
  @end 

 // 
 //    AsyncDownloader.m
  //    VideoDownloader
  // 
 //    Created by Jack Cox on 4/7/12.
  //    
 //
 
 #import   "  AsyncDownloader.h  " 
 #import   "  DownloadProgressView.h  " 

 @implementation   AsyncDownloader

  @synthesize   targetFile;
  @synthesize   srcURL;
  @synthesize   outputHandle;
  @synthesize   tempFile;
  @synthesize   progressView;
  @synthesize   conn;

 - ( void  ) start {
    NSLog(  @"  Starting to download %@  "  , srcURL);
    
      //   create the URL 
    NSURL *url =  [NSURL URLWithString:srcURL];
    
      //   Create the request 
    NSURLRequest *request =  [NSURLRequest requestWithURL:url];
    
      //   create the connection with the target request and this class as the delegate 
    self.conn =  
         [NSURLConnection connectionWithRequest:request 
                                         delegate  :self];
    
      //   start the connection 
     [self.conn start];
}

  /*  *
 * Creates a UUID to use as the temporary file name during the download
   */ 
- (NSString * )createUUID
{
    CFUUIDRef uuidRef  =  CFUUIDCreate(NULL);
    CFStringRef uuidStringRef  =  CFUUIDCreateString(NULL, uuidRef);
    CFRelease(uuidRef);
    NSString  *uuid = [NSString stringWithString:(__bridge NSString * )
                      uuidStringRef];
    CFRelease(uuidStringRef);
      return   uuid;
}
  #pragma  mark NSURLConnectionDelegate methods
 /*  *
 * This delegate method is called when the NSURLConnection gets a 300 series response that indicates
 * that the request needs to be redirected.  It is implemented here to display any redirects that might
 * occur. This method is optional.  If omitted the client will follow all redirects.
 *  */ 
- (NSURLRequest *)connection:(NSURLConnection * )connection 
             willSendRequest:(NSURLRequest  * )request 
            redirectResponse:(NSURLResponse  * )redirectResponse {
    
      //   Dump debugging information 
    NSLog( @"  Redirect request for %@ redirecting to %@  "  , srcURL, request.URL);
    NSLog(  @"  All headers = %@  "  , 
          [(NSHTTPURLResponse * ) redirectResponse allHeaderFields]);
    
      //   Follow the redirect 
     return   request;
}

  /*  *
 * This delegate method is called when the NSURLConnection connects to the server.  It contains the 
 * NSURLResponse object with the headers returned by the server.  This method may be called multiple times.
 * Therefore, it is important to reset the data on each call.  Do not assume that it is the first call
 * of this method.
 *  */ 
- ( void ) connection:(NSURLConnection * )connection 
 didReceiveResponse:(NSURLResponse  * )response {
    NSLog(  @"  Received response from request to url %@  "  , srcURL);
    
    NSHTTPURLResponse  *httpResponse = (NSHTTPURLResponse * )response;
    NSLog(  @"  All headers = %@  "  , [httpResponse allHeaderFields]);
    
      if  (httpResponse.statusCode !=  200 ) { //   something went wrong, abort the whole thing
          //   reset the download counts 
         if  (downloadSize !=  0L  ) {
            [progressView addAmountToDownload: - downloadSize];
            [progressView addAmountDownloaded: - totalDownloaded];
        }
        [connection cancel];
          return  ;
    }
    
    
    NSFileManager  *fm =  [NSFileManager defaultManager];
    
      //   If we have a temp file already, close it and delete it 
     if  (self.tempFile !=  nil) {
        [self.outputHandle closeFile];
        
        NSError  * error;
        [fm removeItemAtPath:self.tempFile error: & error];
    }

      //   remove any pre-existing target file 
    NSError * error;
    [fm removeItemAtPath:targetFile error: & error];
    
      //   get the temporary directory name and make a temp file name 
    NSString *tempDir =  NSTemporaryDirectory();
    self.tempFile  =  [tempDir stringByAppendingPathComponent:[self createUUID]];
    NSLog(  @"  Writing content to %@  "  , self.tempFile);
    
      //   create and open the temporary file 
     [fm createFileAtPath:self.tempFile contents:nil attributes:nil];
    self.outputHandle  =  [NSFileHandle fileHandleForWritingAtPath:self.tempFile];
    
      //   prime the download progress view 
    NSString *contentLengthString = [[httpResponse allHeaderFields] objectForKey: @"  Content-length  "  ];
      //   reset the download counts 
     if  (downloadSize !=  0L  ) {
        [progressView addAmountToDownload: - downloadSize];
        [progressView addAmountDownloaded: - totalDownloaded];
    }
    downloadSize  =  [contentLengthString longLongValue];
    totalDownloaded  =  0L  ;
    
    [progressView addAmountToDownload:downloadSize];
}
  /*  *
 * This delegate method is called for each chunk of data received from the server.  The chunk size
 * is dependent on the network type and the server configuration.  
   */ 
- ( void )connection:(NSURLConnection * )connection 
    didReceiveData:(NSData  * )data {
      //   figure out how many bytes in this chunk 
    totalDownloaded+= [data length];
    
      //   Uncomment if you want a packet by packet log of the bytes received.   
    NSLog( @"  Received %lld of %lld (%f%%) bytes of data for URL %@  "  , 
          totalDownloaded, 
          downloadSize, 
          ((  double )totalDownloaded/( double )downloadSize)* 100.0  ,
          srcURL);
    
      //   inform the progress view that data is downloaded 
     [progressView addAmountDownloaded:[data length]];
    
      //   save the bytes received 
     [self.outputHandle writeData:data];
}

  /*  *
 * This delegate methodis called if the connection cannot be established to the server.  
 * The error object will have a description of the error
 *  */ 
- ( void )connection:(NSURLConnection * )connection 
  didFailWithError:(NSError  * )error {
    NSLog(  @"  Load failed with error %@  "  , 
          [error localizedDescription]);
    
    NSFileManager  *fm =  [NSFileManager defaultManager];
    
      //   If we have a temp file already, close it and delete it 
     if  (self.tempFile !=  nil) {
        [self.outputHandle closeFile];
        
        NSError  * error;
        [fm removeItemAtPath:self.tempFile error: & error];
    }
    
      //   reset the progress view 
     if  (downloadSize !=  0L  ) {
        [progressView addAmountToDownload: - downloadSize];
        [progressView addAmountDownloaded: - totalDownloaded];
    }
}

  /*  *
 * This delegate method is called when the data load is complete.  The delegate will be released 
 * following this call
 *  */ 
- ( void )connectionDidFinishLoading:(NSURLConnection * )connection {
      //   close the file 
     [self.outputHandle closeFile];
    
      //   Move the file to the target location 
    NSFileManager *fm =  [NSFileManager defaultManager];
    NSError  * error;
    [fm moveItemAtPath:self.tempFile 
                toPath:self.targetFile 
                 error: & error];
    
      //   Notify any concerned classes that the download is complete 
     [[NSNotificationCenter defaultCenter] 
     postNotificationName:kDownloadComplete 
       object  :nil 
     userInfo:nil];
}
  @end 

 

 "付出努力的过程也许是举步维艰的,但必须是开心和充实的。“

                                                                                       ----火星人

在挖掘工程代码的过程中,仅仅游走在header文件和源代码文件中往往是意犹未尽的感觉,尤其在实际环境中很难确定某一版本的开源代码真的就是当前系统运行的代码,反正无论怎样,对库文件的汇编追踪都是必不可少的。

汇编代码中的symbol追踪是非常重要的一环,一旦要对库函数做实验,编译测试代码,通过binary tool分析目标代码去hunt down真正的库函数细节!

此篇就是介绍在Mac OS X下这个过程的操作,let's do it.!

最近Mars在研究关于NaN的问题(Orz,写这篇的时候NaN的那篇还不到50%完成度,崩溃中......),那就用相关的代码来介绍一下吧!假设现在写下了下面个这个小羔羊程序:

#include <math.h>

 int   main() {
      double  d0 = nan( "  0xfff0000000001230  "  );
      return   0  ;
} 

这个程序的目标是追踪一下nan这个libc标准函数的实现,在库header里面大家是看不到他嘀~,因为他的实现代码是编译代码。

 gcc  -g -o nan nan.c

看一下编译后汇编代码的主体,因为没有-O选项,所以能看到没有任何优化的原貌:

 _main: 
 Leh_func_begin1:  
        pushq   %rbp
  Ltmp0:  
        movq    %rsp, %rbp
  Ltmp1:  
        subq    $  16  , %rsp
  Ltmp2:  
        leaq    L_.  str  (%rip), %rax
        movq    %rax, %rdi
          callq   _nan
            movsd    %xmm0, - 16  (%rbp)
        movl    $  0 , - 8  (%rbp)
        movl    -  8  (%rbp), %eax
        movl    %eax, -  4  (%rbp)
        movl    -  4  (%rbp), %eax
        addq    $  16  , %rsp
        popq    %rbp
          ret 
 Leh_func_end1: 

从汇编码中看到了"callq _nan",毫无挑战的行踪败露。下一步常规的手段可能会这样做:

otool -L nan

但这样的结果如下:

但事实上在/usr/lib/libSystem.B.dylib中根本不存在_nan的代码,只需要:

nm -a /usr/lib/libSystem.B.dylib |  grep  _nan

就可以知道:

完全没有,就算是存在符号连接也会被nm -a输出来的。

为什么会出现这么奇怪的情况,明明有外部符号,但otool输出的库缺没有这个外部符号的信息?这个问题目前还没找到答案,当另一种追踪符号的方法反而被脑补出来了。

因为下一步要gdb调试,所以带上-g,添加调试符号信息。OK~let's gdb it.

下面分别截图gdb的整个过程:

1)启动gdb看看代码

2)设置断点让程序运行,至于运行到哪里似乎没什么所谓(因为在实验中,把nan的调用嵌入到三重函数嵌套调用中,把断点设置在最外层函数调用之前,也同样可以),因为程序一旦开始执行,就会加载动态链接库的符号。

3)秘密武器出来~

在最后一步,通过info symbol nan就把这个未定义的外部符号最终归属给找出来了!!稍微检验一下:

nm -a /usr/lib/system/libmathCommon.A.dylib |  grep   "  _nan  " 

搞定~找到~接下来就看_nan的代码吧!! 

otool -p  "  _nan  "  -tV /usr/lib/system/libmathCommon.A.dylib

好啦,到这里已经完成对symbol追踪过程的阐述,也故意列出一些otool和nm的使用方法,希望大家受乐啦~毕竟Mac OS X下二进制文件的处理真不太方便,没有了objdump和readelf,虽然可以安装传说中的binutils,但一直没装上,Mars土鳖了。

 

 

分类:  bin ,  tricky ,  mac os x ,  汇编

标签:  mac os x ,  gdb ,  bin ,  otool ,  nm ,  symbol ,  符号

 

分类:  iOS

标签:  iOS网络

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于IOS网络编程:HTTP的详细内容...

  阅读:36次