iOS开发教程Socket的原理和使用.docx

上传人:b****8 文档编号:30130259 上传时间:2023-08-05 格式:DOCX 页数:15 大小:283.56KB
下载 相关 举报
iOS开发教程Socket的原理和使用.docx_第1页
第1页 / 共15页
iOS开发教程Socket的原理和使用.docx_第2页
第2页 / 共15页
iOS开发教程Socket的原理和使用.docx_第3页
第3页 / 共15页
iOS开发教程Socket的原理和使用.docx_第4页
第4页 / 共15页
iOS开发教程Socket的原理和使用.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

iOS开发教程Socket的原理和使用.docx

《iOS开发教程Socket的原理和使用.docx》由会员分享,可在线阅读,更多相关《iOS开发教程Socket的原理和使用.docx(15页珍藏版)》请在冰豆网上搜索。

iOS开发教程Socket的原理和使用.docx

iOS开发教程Socket的原理和使用

iOS开发教程Socket的原理和使用

1.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进行编程。

2.什么是Socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

2.1TCP和UDP的区别

TCP:

面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

UDP:

面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

关于TCP是一种流模式的协议,UDP是一种数据包模式的协议,这里要说明一下,TCP是面向连接的,也就是说,在连接持续的过程中,Socket中收到的数据都是由同一台主机发出的(劫持什么的不考虑),因此,知道保证数据是有序的到达就行了,至于每次读取多少数据自己看着办。

而UDP是无连接的协议,也就是说,只要知道接收端的IP和端口,且网络是可达的,任何主机都可以向接收端发送数据。

这时候,如果一次能读取超过一个报文的数据,则会乱套。

比如,主机A向发送了报文P1,主机B发送了报文P2,如果能够读取超过一个报文的数据,那么就会将P1和P2的数据合并在了一起,这样的数据是没有意义的。

2.2常用的Socket类型

有两种:

流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。

流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

2.2.1TCPC/S架构程序设计基本框架

2.2.2TCP三次握手

最形象理解:

>「你瞅啥?

>

>「瞅你咋地?

>

>「来咱俩唠唠。

>

>然后就唠上了。

2.2.3TCP四次挥手

2.2.4基于TCP的套接字代码实现

相关头文件。

#include

#include

#include

#include

#include

服务端实现代码。

-(void)socketServer

{

interr;

//1.创建socket套接字

//原型:

intsocket(intdomain,inttype,intprotocol);

//domain:

协议族type:

socket类型protocol:

协议

intfd=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

BOOLsuccess=(fd!

=-1);

if(success){

NSLog(@"Socket创建成功");

//地址结构体

structsockaddr_inaddr;

//内存清空

memset(&addr,0,sizeof(addr));

//内存大小

addr.sin_len=sizeof(addr);

//地址族,在socket编程中只能是AF_INET

addr.sin_family=AF_INET;

//端口号

addr.sin_port=htons(1024);

//按照网络字节顺序存储IP地址

addr.sin_addr.s_addr=INADDR_ANY;

//2.建立地址和套接字的联系(绑定)

//原型:

bind(sockid,localaddr,addrlen)

err=bind(fd,(conststructsockaddr*)&addr,sizeof(addr));

success=(err==0);

}

//3.服务器端侦听客户端的请求

if(success){

NSLog(@"绑定成功");

//listen(Sockid,quenlen)quenlen并发队列

err=listen(fd,5);//开始监听

success=(err==0);

}

if(success){

NSLog(@"监听成功");

//4.一直阻塞等到客户端的连接

while(true){

structsockaddr_inpeeraddr;

intpeerfd;

socklen_taddrLen;

addrLen=sizeof(peeraddr);

NSLog(@"等待客户端的连接请求");

//5.服务器端等待从编号为Sockid的Socket上接收客户端连接请求

//原型:

newsockid=accept(Sockid,Clientaddr,paddrlen)

peerfd=accept(fd,(structsockaddr*)&peeraddr,&addrLen);

success=(peerfd!

=-1);

//接收客户端请求成功

if(success){

NSLog(@"接收客户端请求成功,客户端地址:

%s,端口号:

%d",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));

send(peerfd,"欢迎进入Socket聊天室",1024,0);

//6.创建新线程接收客户端发送的消息

[NSThreaddetachNewThreadSelector:

@selector(reciveMessage:

)toTarget:

selfwithObject:

@(peerfd)];

}

}

}

}

-(void)reciveMessage:

(id)peerfd

{

intfd=[peerfdintValue];

charbuf[1024];

ssize_tbufLen;

size_tlen=sizeof(buf);

//循环阻塞接收客户端发送的消息

do{

bufLen=recv(fd,buf,len,0);

//当返回值小于等于零时,表示socket异常或者socket关闭,退出循环阻塞接收消息

if(bufLen<=0){

break;

}

//接收到的信息

NSString*msg=[NSStringstringWithCString:

bufencoding:

NSUTF8StringEncoding];

NSLog(@"来自客户端,消息内容:

%@",msg);

memset(buf,0,sizeof(buf));

}while(true);

//7.关闭

close(fd);

}

客户端代码。

-(void)createSocketClient

{

interr;

//创建socket套接字

intfd=socket(AF_INET,SOCK_STREAM,0);

BOOLsuccess=(fd!

=-1);

structsockaddr_inaddr;

if(success){

NSLog(@"Socket创建成功");

memset(&addr,0,sizeof(addr));

addr.sin_len=sizeof(addr);

addr.sin_family=AF_INET;

addr.sin_addr.s_addr=INADDR_ANY;

//建立地址和套接字的联系

err=bind(fd,(conststructsockaddr*)&addr,sizeof(addr));

success=(err==0);

}

if(success){

structsockaddr_inserveraddr;

memset(&serveraddr,0,sizeof(serveraddr));

serveraddr.sin_len=sizeof(serveraddr);

serveraddr.sin_family=AF_INET;

//服务器端口

serveraddr.sin_port=htons(1024);

//服务器的地址

serveraddr.sin_addr.s_addr=inet_addr("192.168.2.5");

socklen_taddrLen;

addrLen=sizeof(serveraddr);

NSLog(@"连接服务器中...");

err=connect(fd,(structsockaddr*)&serveraddr,addrLen);

success=(err==0);

if(success){

//getsockname是对tcp连接而言。

套接字socket必须是已连接套接字描述符。

err=getsockname(fd,(structsockaddr*)&addr,&addrLen);

success=(err==0);

if(success){

NSLog(@"连接服务器成功,本地地址:

%s,端口:

%d",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));

[NSThreaddetachNewThreadSelector:

@selector(reciveMessage:

)toTarget:

selfwithObject:

@(fd)];

}

}

else{

NSLog(@"connectfailed");

}

}

}

-(void)reciveMessage:

(id)peerfd

{

intfd=[peerfdintValue];

charbuf[1024];

ssize_tbufLen;

size_tlen=sizeof(buf);

//循环阻塞接收消息

do{

bufLen=recv(fd,buf,len,0);

//当返回值小于等于零时,表示socket异常或者socket关闭,退出循环阻塞接收消息

if(bufLen<=0){

break;

}

//接收到的信息

NSString*msg=[NSStringstringWithCString:

bufencoding:

NSUTF8StringEncoding];

NSLog(@"来自服务端,消息内容:

%@",msg);

}while(true);

//7.关闭

close(fd);

}

 

2.2.5UDPC/S架构程序设计基本框架

2.2.6字节顺序

计算机数据表示存在两种字节顺序:

NBO与HBO

网络字节顺序NBO(NetworkByteOrder):

按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。

主机字节顺序(HBO,HostByteOrder):

不同的机器HBO不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关。

不同的CPU有不同的字节顺序类型,这些字节顺序类型指的是整数在内存中保存的顺序,即主机字节顺序。

常见的有两种:

英文名

中文名

描述

big-endian

大尾数顺序

地址的低位存储值的高位

little-endian

小尾数顺序

地址的低位存储值的低位

 

如Intelx86结构下,short型数0x1234表示为3412,int型数0x12345678表示为78563412如IBMpowerPC结构下,short型数0x1234表示为1234,int型数0x12345678表示为12345678

网络字节顺序与本地字节顺序之间的转换函数:

htonl()--"HosttoNetworkLong"

ntohl()--"NetworktoHostLong"

htons()--"HosttoNetworkShort"

ntohs()--"NetworktoHostShort"

2.2.7地址转换方法

in_addr_tinet_addr(constchar*)

将一个点间隔地址转换成一个in_addr

char*inet_ntoa(structin_addr)

将网络地址转换成“.”点隔的字符串格式。

intinet_aton(constchar*,structin_addr*)

将一个字符串IP地址转换为一个32位的网络序列IP地址。

2.2.8获取地址

-用getsockname获得本地ip和port

-用getpeername获得对端ip和port

套接字socket必须是已连接套接字描述符。

2.2.9获取本地IP地址

参考stackoverflow链接:

<

2.2.10UPD套接字实现代码

#include

-(NSString*)getIPAddress{

NSString*address=@"error";

structifaddrs*interfaces=NULL;

structifaddrs*temp_addr=NULL;

intsuccess=0;

//retrievethecurrentinterfaces-returns0onsuccess

success=getifaddrs(&interfaces);

if(success==0){

//Loopthroughlinkedlistofinterfaces

temp_addr=interfaces;

while(temp_addr!

=NULL){

if(temp_addr->ifa_addr->sa_family==AF_INET){

//Checkifinterfaceisen0whichisthewificonnectionontheiPhone

if([[NSStringstringWithUTF8String:

temp_addr->ifa_name]isEqualToString:

@"en0"]){

//GetNSStringfromCString

address=[NSStringstringWithUTF8String:

inet_ntoa(((structsockaddr_in*)temp_addr->ifa_addr)->sin_addr)];

}

}

temp_addr=temp_addr->ifa_next;

}

}

//Freememory

freeifaddrs(interfaces);

returnaddress;

}

 

3.第三方库

CocoaAsyncSocket:

<

CocoaAsyncSocketprovideseasy-to-useandpowerfulasynchronoussocketlibrariesforMacandiOS.Theclassesaredescribedbelow.

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 职业教育 > 中职中专

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1