iOS网络编程之Socket.docx
- 文档编号:5221210
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:9
- 大小:61.97KB
iOS网络编程之Socket.docx
《iOS网络编程之Socket.docx》由会员分享,可在线阅读,更多相关《iOS网络编程之Socket.docx(9页珍藏版)》请在冰豆网上搜索。
iOS网络编程之Socket
iOS网络编程之Socket
一,iOS网络编程层次模型
在前文《深入浅出Cocoa之Bonjour网络编程》中我介绍了如何在Mac系统下进行Bonjour编程,在那篇文章中也介绍过Cocoa中网络编程层次结构分为三层,虽然那篇演示的是Mac系统的例子,其实对iOS系统来说也是一样的。
iOS网络编程层次结构也分为三层:
∙Cocoa层:
NSURL,Bonjour,GameKit,WebKit
∙CoreFoundation层:
基于C的 CFNetwork和CFNetServices
∙OS层:
基于C的BSDsocket
Cocoa层是最上层的基于Objective-C的API,比如URL访问,NSStream,Bonjour,GameKit等,这是大多数情况下我们常用的API。
Cocoa层是基于CoreFoundation实现的。
CoreFoundation层:
因为直接使用socket需要更多的编程工作,所以苹果对OS层的socket进行简单的封装以简化编程任务。
该层提供了CFNetwork和CFNetServices,其中CFNetwork又是基于CFStream和CFSocket。
OS层:
最底层的BSDsocket提供了对网络编程最大程度的控制,但是编程工作也是最多的。
因此,苹果建议我们使用CoreFoundation及以上层的API进行编程。
本文将介绍如何在iOS系统下使用最底层的socket进行编程,这和在window系统下使用C/C++进行socket编程并无多大区别。
本文源码:
运行效果如下:
二,BSDsocketAPI简介
BSDsocketAPI和winsockAPI接口大体差不多,下面将列出比较常用的API:
API接口
讲解
intsocket(intaddressFamily,inttype,
intprotocol)
intclose(intsocketFileDescriptor)
socket 创建并初始化socket,返回该socket的文件描述符,如果描述符为-1表示创建失败。
通常参数addressFamily是IPv4(AF_INET)或IPv6(AF_INET6)。
type表示socket的类型,通常是流stream(SOCK_STREAM)或数据报文datagram(SOCK_DGRAM)。
protocol参数通常设置为0,以便让系统自动为选择我们合适的协议,对于streamsocket来说会是TCP协议(IPPROTO_TCP),而对于datagram来说会是UDP协议(IPPROTO_UDP)。
close 关闭socket。
intbind(intsocketFileDescriptor,
sockaddr*addressToBind,
intaddressStructLength)
将socket与特定主机地址与端口号绑定,成功绑定返回0,失败返回-1。
成功绑定之后,根据协议(TCP/UDP)的不同,我们可以对socket进行不同的操作:
UDP:
因为UDP是无连接的,绑定之后就可以利用UDPsocket传送数据了。
TCP:
而TCP是需要建立端到端连接的,为了建立TCP连接服务器必须调用listen(intsocketFileDescriptor,intbacklogSize)来设置服务器的缓冲区队列以接收客户端的连接请求,backlogSize表示客户端连接请求缓冲区队列的大小。
当调用listen设置之后,服务器等待客户端请求,然后调用下面的accept来接受客户端的连接请求。
intaccept(intsocketFileDescriptor,
sockaddr*clientAddress,int
clientAddressStructLength)
接受客户端连接请求并将客户端的网络地址信息保存到clientAddress中。
当客户端连接请求被服务器接受之后,客户端和服务器之间的链路就建立好了,两者就可以通信了。
intconnect(intsocketFileDescriptor,
sockaddr*serverAddress,int
serverAddressLength)
客户端向特定网络地址的服务器发送连接请求,连接成功返回0,失败返回-1。
当服务器建立好之后,客户端通过调用该接口向服务器发起建立连接请求。
对于UDP来说,该接口是可选的,如果调用了该接口,表明设置了该UDPsocket默认的网络地址。
对 TCPsocket来说这就是传说中三次握手建立连接发生的地方。
注意:
该接口调用会阻塞当前线程,直到服务器返回。
hostent*gethostbyname(char*hostname)
使用DNS查找特定主机名字对应的IP地址。
如果找不到对应的IP地址则返回NULL。
intsend(intsocketFileDescriptor,char
*buffer,intbufferLength,intflags)
通过socket发送数据,发送成功返回成功发送的字节数,否则返回-1。
一旦连接建立好之后,就可以通过send/receive接口发送或接收数据了。
注意调用connect设置了默认网络地址的UDPsocket也可以调用该接口来接收数据。
intreceive(intsocketFileDescriptor,
char*buffer,intbufferLength,intflags)
从socket中读取数据,读取成功返回成功读取的字节数,否则返回-1。
一旦连接建立好之后,就可以通过send/receive接口发送或接收数据了。
注意调用connect设置了默认网络地址的UDPsocket也可以调用该接口来发送数据。
intsendto(intsocketFileDescriptor,
char*buffer,intbufferLength,int
flags,sockaddr*destinationAddress,int
destinationAddressLength)
通过UDPsocket发送数据到特定的网络地址,发送成功返回成功发送的字节数,否则返回-1。
由于UDP可以向多个网络地址发送数据,所以可以指定特定网络地址,以向其发送数据。
intrecvfrom(intsocketFileDescriptor,
char*buffer,intbufferLength,int
flags,sockaddr*fromAddress,int
*fromAddressLength)
从UDPsocket中读取数据,并保存发送者的网络地址信息,读取成功返回成功读取的字节数,否则返回-1 。
由于UDP可以接收来自多个网络地址的数据,所以需要提供额外的参数,以保存该数据的发送者身份。
三,服务器工作流程
有了上面的socketAPI讲解,下面来总结一下服务器的工作流程。
1.服务器调用socket(...)创建socket;
2.服务器调用listen(...)设置缓冲区;
3.服务器通过accept(...)接受客户端请求建立连接;
4.服务器与客户端建立连接之后,就可以通过send(...)/receive(...)向客户端发送或从客户端接收数据;
5.服务器调用close关闭socket;
由于iOS设备通常是作为客户端,因此在本文中不会用代码来演示如何建立一个iOS服务器,但可以参考前文:
《深入浅出Cocoa之Bonjour网络编程》看看如何在Mac系统下建立桌面服务器。
四,客户端工作流程
由于iOS设备通常是作为客户端,下文将演示如何编写客户端代码。
先来总结一下客户端工作流程。
1.客户端调用socket(...) 创建socket;
2.客户端调用connect(...)向服务器发起连接请求以建立连接;
3.客户端与服务器建立连接之后,就可以通过send(...)/receive(...)向客户端发送或从客户端接收数据;
4.客户端调用close关闭socket;
五,客户端代码示例
下面的代码就实现了上面客户端的工作流程:
-(void)loadDataFromServerWithURL:
(NSURL*)url
{
NSString*host=[urlhost];
NSNumber*port=[urlport];
//Createsocket
//
intsocketFileDescriptor=socket(AF_INET,SOCK_STREAM,0);
if(-1==socketFileDescriptor){
NSLog(@"Failedtocreatesocket.");
return;
}
//GetIPaddressfromhost
//
structhostent*remoteHostEnt=gethostbyname([hostUTF8String]);
if(NULL==remoteHostEnt){
close(socketFileDescriptor);
[selfnetworkFailedWithErrorMessage:
@"Unabletoresolvethehostnameofthewarehouseserver."];
return;
}
structin_addr*remoteInAddr=(structin_addr*)remoteHostEnt->h_addr_list[0];
//Setthesocketparameters
//
structsockaddr_insocketParameters;
socketParameters.sin_family=AF_INET;
socketParameters.sin_addr=*remoteInAddr;
socketParameters.sin_port=htons([portintValue]);
//Connectthesocket
//
intret=connect(socketFileDescriptor,(structsockaddr*)&socketParameters,sizeof(socketParameters));
if(-1==ret){
close(socketFileDescriptor);
NSString*errorInfo=[NSStringstringWithFormat:
@">>Failedtoconnectto%@:
%@",host,port];
[selfnetworkFailedWithErrorMessage:
errorInfo];
return;
}
NSLog(@">>Successfullyconnectedto%@:
%@",host,port);
NSMutableData*data=[[NSMutableDataalloc]init];
BOOLwaitingForData=YES;
//Continuallyreceivedatauntilwereachtheendofthedata
//
intmaxCount=5;//justfortest.
inti=0;
while(waitingForData&&i constchar*buffer[1024]; intlength=sizeof(buffer); //Readabuffer'samountofdatafromthesocket;thenumberofbytesreadisreturned // intresult=recv(socketFileDescriptor,&buffer,length,0); if(result>0){ [dataappendBytes: bufferlength: result]; } else{ //ifwedidn'tgetanydata,stopthereceiveloop // waitingForData=NO; } ++i; } //Closethesocket // close(socketFileDescriptor); [selfnetworkSucceedWithData: data]; } 前面说过,connect/recv/send等接口都是阻塞式的,因此我们需要将这些操作放在非UI线程中进行。 如下所示: NSThread*backgroundThread=[[NSThreadalloc]initWithTarget: self selector: @selector(loadDataFromServerWithURL: ) object: url]; [backgroundThreadstart]; 同样,在获取到数据或者网络异常导致任务失败,我们需要更新UI,这也要回到UI线程中去做这个事情。 如下所示: -(void)networkFailedWithErrorMessage: (NSString*)message { //UpdateUI // [[NSOperationQueuemainQueue]addOperationWithBlock: ^{ NSLog(@"%@",message); self.receiveTextView.text=message; self.connectButton.enabled=YES; [workActivityViewstopAnimating]; }]; } -(void)networkSucceedWithData: (NSData*)data { //UpdateUI // [[NSOperationQueuemainQueue]addOperationWithBlock: ^{ NSString*resultsString=[[NSStringalloc]initWithData: dataencoding: NSUTF8StringEncoding]; NSLog(@">>Receivedstring: '%@'",resultsString); self.receiveTextView.text=resultsString; self.connectButton.enabled=YES; [workActivityViewstopAnimating]; }]; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- iOS 网络 编程 Socket
![提示](https://static.bdocx.com/images/bang_tan.gif)