智汇工业-智慧工业、智能制造及工业智能、工业互联门户网站,专业的工业“互联网+”传媒

玩轉iPhone網絡通訊之BSD Socket篇

來源:網絡

點擊:1607

A+ A-

所屬頻道:新聞中心

關鍵詞: iPhone,網絡通訊,BSD Socket

      在進行iPhone網絡通訊程序的開發中,不可避免的要利用Socket套接字。iPhone提供了Socket網絡編程的接口CFSocket,不過筆者更喜歡使用BSD Socket。

      iPhone BSD Socket進行編程所需要的頭文件基本都位于/Xcode3.1.4/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/usr/include/sys下,既然本篇文章作為基礎篇,那么筆者就從最基本的知識講解開始。

      首先,Socket是進行程序間通訊(IPC, Internet Process Connection)的BSD方法,這意味著Socket是用來讓一個進程和其他的進程互相通訊的,就像我們用電話來和其他人交流一樣。

      既然說Socket像個電話,那么如果要打電話首先就要安裝一部電話,“安裝電話”這個動作對BSD Socket來說就是初始化一個Socket,方法如下:

      int socket(int, int, int);

      第一個int參數為Socket的地址方式,既然要“安裝電話”,那么就要首先確認所要安裝的電話是音頻的還是脈沖的。而如果要給BSD Socket安裝電話,有兩種類型可供讀者選擇:AF_UNIX和AF_INET,它們代表Socket的地址格式。如果選擇AF_UNIX,意味著需要為Socket提供一個類似Unix路徑的名稱,這個選項主要用于本地程序之間的socket通訊;本文主要講解網絡通訊,所以需要選擇參數AF_INET。

      第二個int參數為Socket的類型,“安裝電話”需要首先確定是裝有線的還是裝無線的,安裝Socket也一樣,在Socket中提供了兩種類型:SOCK_STREAM和SOCK_DGRAM。SOCK_STREAM表明數據像字符流一樣通過Socket;而SOCK_DGRAM則表明數據以數據報(Datagrams)的形式通過Socket,本文主要講解SOCK_STREAM,因為它的使用更為廣泛。

      第三個int參數為所使用的協議,本文里使用0即可。

      “安裝電話”的代碼如下:

      if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

      {

      perror(“socket”);

      exit(1);

      }

      到現在為止,怎么安裝電話已經清楚了。因為本文主要演示如何在iPhone上使用BSD Socket獲取內容,更多的功能是“打電話”而不是“接電話”,所以下面主要講解BSD Socket扮演“客戶端”角色的操作。

      既然要“打電話”,那么首先要有打電話的對象,更確切的說需要一個“電話號碼”,BSD Socket中的“電話號碼”就是IP地址。更糟糕的情況是,如果只知道聯系人的名字而不知道電話號碼,那么還需要程序查找相應聯系人的電話號碼,根據聯系人姓名查找電話號碼的過程在BSD Socket中叫做DNS解析,代碼如下:

      - (NSString*)getIpAddressForHost:(NSString*) theHost

      {

      struct hostent *host = gethostbyname([theHost UTF8String]);

      if(!host)

      {

      herror(“resolv”);

      return NULL;

      }

      struct in_addr **list = (struct in_addr **)host-》h_addr_list;

      NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0])];

      return addressString;

      }

      hostent是個結構體,使用它需要#import 《netdb.h》,通過這個方法得到theHost域名的第一個有效的IP地址并返回。

      正確的“找到電話號碼”后,就需要“撥打電話”了,代碼如下:

      their_addr.sin_family = AF_INET;

      their_addr.sin_addr.s_addr = inet_addr([[self getIpAddressForHost:hostName] UTF8String]);

      NSLog(@“getIpAddressForHost :%@”,[self getIpAddressForHost:hostName]);

      their_addr.sin_port = htons(80);

      bzero(&(their_addr.sin_zero), 8);

      int conn = connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr));

      NSLog(@“Connect errno is :%d”,conn);

      筆者最初試圖采用NHost進行主機域名的解析,奈何iPhone的這個類為private的,在application的開發中不可使用。

      如果“電話”能順利的接通,那么就可以進行“講話”了,反之則會斷開“電話連接”,如果友好的話,最好能給個提示,諸如“您所撥打的電話不在服務區之類”:)

      if(conn != -1)

      {

      NSLog(@“Then the conn is not -1!”);

      NSMutableString* httpContent = [self makeHttpHeader:hostName];

      NSLog(@“httpCotent is :%@”,httpContent);

      if(contentSended != nil)

     ?。踙ttpContent appendFormat:contentSended];

      NSLog(@“Sended content is :%@”,httpContent);

      NSData *data = [httpContent dataUsingEncoding:NSISOLatin1StringEncoding];

      ssize_t dataSended = send(sockfd, [data bytes], [data length], 0);

      if(dataSended == [data length])

      {

      NSLog(@“Datas have been sended over!”);

      }

      printf(“send %d bytes to %s\n”,dataSended,inet_ntoa(their_addr.sin_addr));

      NSMutableString* readString = [[NSMutableString alloc] init];

      char readBuffer[512];

      int br = 0;

      while((br = recv(sockfd, readBuffer, sizeof(readBuffer), 0)) 《 sizeof(readBuffer))

      {

      NSLog(@“read datas length is :%d”,br);

      [readString appendFormat:[NSString stringWithCString:readBuffer length:br]];

      NSLog(@“Hava received datas is :%@”,readString);

      }

      close(sockfd);

      }else {

      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[@“Connection failed to host ” stringByAppendingString:hostName] message:@“Please check the hostname in the preferences.” delegate:self cancelButtonTitle:@“OK” otherButtonTitles:nil];

     ?。踑lert show];

      [alert release];

      }

      “講話”通過send(),“聽話”通過recv(),這個兩個函數的原型如下:

      int send(int sockfd, const void *msg, int len, int flags);

      int recv(int sockfd,void *buf,int len,unsigned int flags);

      可以看出,這兩個函數的參數基本相同。

      第一個參數為套接字的句柄。

      第二個參數為數據緩沖區。

      第三個參數為數據長度。

      最后一個參數有點特殊,這個參數是為了讓BSD Socket能支持“帶外數據”,何謂“帶外數據”?顧名思義,就是“帶內以外的數據”,而帶內數據就是常規的按照Socket字節流順序進行傳遞的數據。通常情況下,數據由連接的一端流到接收的一端,并且認為數據的所有字節都是精確排序的,晚寫入的字節絕不會早于先寫入的字節到達。但是如果我們“掛斷了電話”,而接收方還有大量已經被接收的緩沖數據,這些數據還沒被程序讀取,那么接收方需要在讀取這些緩沖的“帶內數據”之前先讀取一個標識取消的請求,這個請求就可以利用帶外請求的方法進行傳送。請求帶外數據傳送需要把標識位置為MSG_OOB,如下:

      char buf[64];

      int len;

      int s;

      …

      send(s,buf,len,MSG_OOB);

      至此,一個完整的“通話過程”已經結束,最后別忘記調用close(sockfd)“掛斷電話”。

      下面筆者嘗試請求www.baidu.com的首頁,并把請求的頁面內容打印到控制臺,所以需要對請求進行封裝,以支持HTTP協議。很簡單,只需要在請求的內容前面加上相應的HTTP頭信息即可,如下:

      #define HTTPMETHOD @“GET”

      #define HTTPVERSION @“HTTP/1.1”

      #define HTTPHOST @“Host”

      #define KENTER @“\r\n”

      #define KBLANK @“ ”

      - (NSMutableString*) makeHttpHeader:(NSString*) hostName

      {

      NSMutableString *header = [[NSMutableString alloc] init];

      [header appendFormat:HTTPMETHOD];

     ?。踙eader appendFormat:KBLANK];

     ?。踙eader appendFormat:@“/index.html”];

     ?。踙eader appendFormat:KBLANK];

     ?。踙eader appendFormat:HTTPVERSION];

      [header appendFormat:KENTER];

      [header appendFormat:HTTPHOST];

      [header appendFormat:@“:”];

      [header appendFormat:hostName];

      [header appendFormat:KENTER];

      [header appendFormat:KENTER];

      return header;

      }

      在上面的方法中,筆者封裝了HTTP頭信息,對HTTP不熟悉的同學可以先熟悉熟悉HTTP的格式,請求到的內容打印如下:

     ?。跾ession started at 2009-11-12 15:40:02 +0800.]

      2009-11-12 15:40:04.691 BSDHttpExample[3483:207] getIpAddressForHost :119.75.216.30

      2009-11-12 15:40:04.725 BSDHttpExample[3483:207] Connect errno is :0

      2009-11-12 15:40:04.727 BSDHttpExample[3483:207] Then the conn is not -1!

      2009-11-12 15:40:04.735 BSDHttpExample[3483:207] httpCotent is :GET /index.html HTTP/1.1

      Host:www.baidu.com

      2009-11-12 15:40:04.736 BSDHttpExample[3483:207] Sended content is :GET /index.html HTTP/1.1

      Host:www.baidu.com

      2009-11-12 15:40:04.736 BSDHttpExample[3483:207] Datas have been sended over!

      send 48 bytes to 119.75.216.30

      2009-11-12 15:40:04.764 BSDHttpExample[3483:207] read datas length is :363

      2009-11-12 15:40:04.765 BSDHttpExample[3483:207] Hava received datas is :HTTP/1.1 200 OK

      Date: Thu, 12 Nov 2009 07:40:05 GMT

      Server: BWS/1.0

      Content-Length: 3520

      Content-Type: text/html;charset=gb2312

      Cache-Control: private

      Expires: Thu, 12 Nov 2009 07:40:05 GMT

      Set-Cookie: BAIDUID=9B024266ADD3B52AC8367A2BDD1676E5:FG=1; expires=Thu, 12-Nov-39 07:40:05 GMT; path=/; domain=.baidu.com

      P3P: CP=“ OTI DSP COR IVA OUR IND COM ”

      2009-11-12 15:40:04.766 BSDHttpExample[3483:207] view has been loaded!

      最后為了造福大家,筆者附上完整的代碼,頭文件如下:

      //

      // BSDHttpExampleViewController.h

      // BSDHttpExample

      //

      // Created by sun dfsun2009 on 09-11-12.

      // Copyright __MyCompanyName__ 2009. All rights reserved.

      //

      #import 《UIKit/UIKit.h》

      #define MYPORT 4880

      #import 《stdio.h》

      #import 《stdlib.h》

      #import 《unistd.h》

      #import 《arpa/inet.h》

      #import 《sys/types.h》

      #import 《sys/socket.h》

      #import 《netdb.h》

      @interface BSDHttpExampleViewController : UIViewController {

      int sockfd;

      struct sockaddr_in their_addr;

      }

      @end

      實現文件如下:

      //

      // BSDHttpExampleViewController.m

      // BSDHttpExample

      //

      // Created by sun dfsun2009 on 09-11-12.

      // Copyright __MyCompanyName__ 2009. All rights reserved.

      //

      #import “BSDHttpExampleViewController.h”

      @implementation BSDHttpExampleViewController

      #define HTTPMETHOD @“GET”

      #define HTTPVERSION @“HTTP/1.1”

      #define HTTPHOST @“Host”

      #define KENTER @“\r\n”

      #define KBLANK @“ ”

      /*

      // The designated initializer. Override to perform setup that is required before the view is loaded.

      - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

      if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {

      // Custom initialization

      }

      return self;

      }

      */

      /*

      // Implement loadView to create a view hierarchy programmatically, without using a nib.

      - (void)loadView {

      }

      */

      void error_handle(char *errorMsg)

      {

      fputs(errorMsg, stderr);

      fputc(‘\n’,stderr);

      exit(1);

      }

      - (NSMutableString*) makeHttpHeader:(NSString*) hostName

      {

      NSMutableString *header = [[NSMutableString alloc] init];

      [header appendFormat:HTTPMETHOD];

      [header appendFormat:KBLANK];

      [header appendFormat:@“/index.html”];

     ?。踙eader appendFormat:KBLANK];

      [header appendFormat:HTTPVERSION];

      [header appendFormat:KENTER];

     ?。踙eader appendFormat:HTTPHOST];

      [header appendFormat:@“:”];

      [header appendFormat:hostName];

     ?。踙eader appendFormat:KENTER];

      [header appendFormat:KENTER];

      return header;

      }

      - (NSString*)getIpAddressForHost:(NSString*) theHost

      {

      struct hostent *host = gethostbyname([theHost UTF8String]);

      if(!host)

      {

      herror(“resolv”);

      return NULL;

      }

      struct in_addr **list = (struct in_addr **)host-》h_addr_list;

      NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0])];

      return addressString;

      }

      - (void)Connect:(NSString *)hostName content:(NSString *)contentSended

      {

      if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

      {

      perror(“socket”);

      exit(1);

      }

      //NSHost *host = [NSHost hostWithName:hostName];

      //if(host)

      //{

      their_addr.sin_family = AF_INET;

      //their_addr.sin_addr.s_addr = inet_addr([[host address] UTF8String]);

      their_addr.sin_addr.s_addr = inet_addr([[self getIpAddressForHost:hostName] UTF8String]);

      NSLog(@“getIpAddressForHost :%@”,[self getIpAddressForHost:hostName]);

      their_addr.sin_port = htons(80);

      bzero(&(their_addr.sin_zero), 8);

      int conn = connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr));

      NSLog(@“Connect errno is :%d”,conn);

      if(conn != -1)

      {

      NSLog(@“Then the conn is not -1!”);

      NSMutableString* httpContent = [self makeHttpHeader:hostName];

      NSLog(@“httpCotent is :%@”,httpContent);

      if(contentSended != nil)

      [httpContent appendFormat:contentSended];

      NSLog(@“Sended content is :%@”,httpContent);

      NSData *data = [httpContent dataUsingEncoding:NSISOLatin1StringEncoding];

      ssize_t dataSended = send(sockfd, [data bytes], [data length], 0);

      if(dataSended == [data length])

      {

      NSLog(@“Datas have been sended over!”);

      }

      printf(“send %d bytes to %s\n”,dataSended,inet_ntoa(their_addr.sin_addr));

      NSMutableString* readString = [[NSMutableString alloc] init];

      char readBuffer[512];

      int br = 0;

      while((br = recv(sockfd, readBuffer, sizeof(readBuffer), 0)) 《 sizeof(readBuffer))

      {

      NSLog(@“read datas length is :%d”,br);

     ?。踨eadString appendFormat:[NSString stringWithCString:readBuffer length:br]];

      NSLog(@“Hava received datas is :%@”,readString);

      }

      close(sockfd);

      }else {

      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[@“Connection failed to host ” stringByAppendingString:hostName] message:@“Please check the hostname in the preferences.” delegate:self cancelButtonTitle:@“OK” otherButtonTitles:nil];

     ?。踑lert show];

     ?。踑lert release];

      }

      /*

      }

      else

      {

      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[@“Could not look up host ” stringByAppendingString:hostName] message:@“Please check the hostname in the preferences.” delegate:self cancelButtonTitle:@“OK” otherButtonTitles:nil];

      [alert show];

     ?。踑lert release];

      }

      **/

      }

      - (void)Send:(id)sender

      {

      char message[7] = “aaag”;

      send(sockfd,message,sizeof(message),0);

      NSLog(@“%s”,message);

      }

      // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

      - (void)viewDidLoad {

     ?。踫elf Connect:@“www.baidu.com” content:nil];

     ?。踫uper viewDidLoad];

      NSLog(@“view has been loaded!”);

      }

      /*

      // Override to allow orientations other than the default portrait orientation.

      - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

      // Return YES for supported orientations

      return (interfaceOrientation == UIInterfaceOrientationPortrait);

      }

      */

      - (void)didReceiveMemoryWarning {

      // Releases the view if it doesn‘t have a superview.

     ?。踫uper didReceiveMemoryWarning];

      // Release any cached data, images, etc that aren’t in use.

      }

      - (void)viewDidUnload {

      // Release any retained subviews of the main view.

      // e.g. self.myOutlet = nil;

      }

      - (void)dealloc {

      [super dealloc];

      }

      @end

    (審核編輯: 智匯小新)

    聲明:除特別說明之外,新聞內容及圖片均來自網絡及各大主流媒體。版權歸原作者所有。如認為內容侵權,請聯系我們刪除。

    主站蜘蛛池模板: 学汽修,学汽修技术,汽修培训班,汽车美容培训,汽车新能源技术培训-广州万通汽车培训学校[官方网站] | 济南德固机械|膨化食品生产线|早餐谷物玉米片生产线|拉丝蛋白生产线|速食米饭生产线 | 旋风铣_数控旋风铣整机_旋风铣头|定制生产厂家【腾创机械厂官网】 | 木别墅-小木屋-防腐木木屋-成都腾龙装配式建筑科技有限公司 | 纳米砂磨机|纳米研磨机|实验室砂磨机-无锡市少宏粉体科技有限公司 | 江苏广分检测技术有限公司、电力安全工具检测、苏州绝缘工具检测、昆山电力安全工具检测-广分检测技术(苏州)有限公司 | 山东汇河环保科技集团有限公司,水囊水袋,水罐,油囊,预压水袋,吊重水袋_山东汇河环保科技集团有限公司,水囊水袋,水罐,油囊,预压水袋,吊重水袋 | 系统门窗加盟_门窗十大品牌_欧享门窗官网 | 洒水车厂家、消防车、污水处理车厂家-程力专用汽车股份有限公司 洒水车|冷藏车|LED广告车|油罐车|道路救援车|垃圾车|程力专用汽车股份有限公司销售九分公司 | 山西洗煤设备_山西洗煤机_山西离心机-山西东鑫昶机械科技股份有限公司 | 木马交互设计研究中心 ,专注于用户体验与人机交互设计 - 首页 | 全功能护理训练模拟人-创伤护理人-高级电脑心肺复苏模型-上海康季 | 叛逆孩子改造,青少年行为矫正,戒网瘾学校,特训学校,全封闭军事化管理学校 | 仪器仪表维修_示波器维修_进口分析仪维修_热像仪维修_上海仰光电子仪器仪表维修部 | 无缝钢管生产厂家-20G-L360N无缝钢管价格-天津海诚无缝钢管集团 无尘投料站-真空上料机-旋振筛|超声波振动筛|摇摆筛|筛分机-新乡市欧霖佳机械有限公司 | 升降机_举升机_液压升降机_化工防爆升降平台_山东华雄机械有限公司 | 涂料分散剂_水墨分散剂-厚洹化学水性色浆助剂厂家 | 昆明塑料包装袋|云南塑料包装袋|昆明塑料袋厂家|云南茶叶大米蔬菜种子食品包装袋就来阮门包装有限公司 | 苏州妙凯电子有限公司-供应军工电源芯片|线性恒流IC|开关电源IC|LED驱动芯片|MOS管|IPM|IGBT|MCU开发|电源模块 | 卫生间隔断-东莞卫生间隔断-东莞卫生间隔断厂家-公共卫生间隔断-东莞市康丰家居建材有限公司 | 企业资质代办-代理全国工商注册公司_公司转让_增值电信业务许可证新办续期-大通天成科技[gw] | 湖南视频会议设备厂家|长沙视频会议设备安装型号齐全找湖南日恒智能工程有限公司 | 户外工程照明|洗墙灯厂家|聚翔(广东)照明科技有限公司 | 易众拍卖行-事故车拍卖,残值车拍卖,水淹车拍卖,全损车拍卖,修复车拍卖,碰橦车拍卖,瑕疵车拍卖,报废车拍卖,泡水车拍卖,拆车件拍卖,配件拍卖,火烧车拍卖,二手车拍卖专业线上平台 | 以物联网技术为核心专注于智能安防领域物联网服务的高新技术企业-北京欣智恒科技股份有限公司(官网) | 声测管厂家_注浆管现货_桩基声测管_河北沧州新迈实业有限公司 | 展会设计搭建-展厅设计施工公司-展位展台设计搭建-深圳鼎泰展览 展柜设计定制-品牌展柜订做-展柜制作厂家「广州嘉艺展柜」 | 重庆吊篮租赁-重庆脚手架租赁-重庆斌盛机械设备租赁有限公司 | 消防安装_消防安装施工_消防施工_北京消防安装公司-亿杰(北京)消防工程有限公司 | 皮带清扫器-皮带聚氨酯合金空段输送带清扫器刮刀厂家-衡水格锐特机械科技有限公司 | 离婚协议书怎么写_离婚协议书模板标准版_离婚协议书范本下载 - 离婚协议书 | 全自动高速点胶机,锡膏喷印机系列,点胶阀核心配件厂家-博宁 | 拉力机|拉力试验机|拉力测试机厂家-苏州天氏库力精密仪器有限公司 | 品牌策划-品牌设计-济南之式传媒广告有限公司官网-提供品牌整合丨影视创意丨公关活动丨数字营销丨自媒体运营丨数字营销 | 泰安兴润建材有限公司,泰安井盖定做,泰安警示桩定做,泰安雨水篦子定做,泰安操场篦子定做,泰安标志牌定做 | 全自动视觉点胶机|在线式点胶机|精密点胶阀设备厂家-杭州迈伺特科技有限公司 | 普利塞HS穿刺活检针-巴德穿刺活检针-美创爱琅Argon活检针同轴针-山东瑞玺源 | 墨子百科-专业有趣的问题小百科 莫非传媒官网-江西知名的网络营销推广服务平台南昌网络公司,专业网络公关,品牌危机处理,网站SEO优化,微信朋友圈广告,网站建设,南昌莫非文化传媒有限公司 | 葫芦岛市鹏翔农药化工科技有限公司-苦参碱可溶液剂-氯氰菊酯乳油-阿维菌素乳油 | 轮转印刷机_商标印唛机_超声波切唛机_瑞安市明辉机械有限公司 | 上海办公室装修公司|办公室装修设计|上海写字楼装修【半尺砚装饰】 |