您的位置:首页 > 移动开发 > IOS开发

iOS and OS X Network Programming Cookbook |Performing a network address resolution

2015-06-30 20:23 609 查看
这个部分解决的是host/service name 和 sockadd structure相互转换的问题。

用到的两个方法:

Getaddrinfo():通过给定的host/service name返回相关信息,存储在addrinfo structure中.

Getnameinfo():使用给定的sockaddr structure得到host/service name。

主要步骤(BSD版本):

1.创建一个AddrInfo类,继承自NSObject

#import <netdb.h>
#import <netinet/in.h>
#import <netinet6/in6.h>

@property (nonatomic, strong) NSString *hostname, *service;
@property (nonatomic) struct addrinfo *results;
@property (nonatomic) struct sockaddr *sa;
@property (nonatomic, readonly) int errorCode;
-(void)addrWithHostname:(NSString*)lHostname Service:(NSString *)
lService andHints:(struct addrinfo*)lHints;
-(void)nameWithSockaddr:(struct sockaddr *)saddr;
-(NSString *)errorString;


这其中定义的第一个方法将会使用getaddrinfo()方法得到results,第二个方法使用getnameinfo()得到hostname和serviece。

2.实现AddInfo类

-(void)setVars {
self.hostname = @"";
self.service = @"";
self.results = @"";
_errorCode = 0;
}

-(void)addrWithHostname:(NSString*)lHostname Service:(NSString *)
lService andHints:(struct addrinfo*)lHints {
[self setVars];
self.hostname = lHostname;
self.service = lService;
struct addrinfo *res;
_errorCode = getaddrinfo([_hostname UTF8String], [_service
UTF8String], lHints, &res);
self.results = res;
}


getaddrinfo()中需要的hostname和service的格式是char array格式,所以要进行转换。如果成功的话errorcode = 0

-(void)nameWithSockaddr:(struct sockaddr *)saddr {
[self setVars];
char host[1024];
char serv[20];
_errorCode = getnameinfo(saddr, sizeof saddr, host, sizeof host,
serv, sizeof serv, 0);
self.hostname = [NSString stringWithUTF8String:host];
self.service = [NSString stringWithUTF8String:serv];
}
代码非常简洁明了,差不多就是上面代码的逆向,成功返回0,不成功返回-1

-(void)setResults:(struct addrinfo *)lResults {
abac
freeaddrinfo(self.results);
_results = lResults;
}


在results设置新值前释放旧值

3.main函数中的调用

</pre><pre name="code" class="objc">struct addrinfo *res;
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

AddrInfo *ai = [[AddrInfo alloc] init];
[ai addrWithHostname:@"www.packtpub.com" Service:@"443"
andHints:&hints];
struct addrinfo *results = ai.results;
for (res = results; res!= NULL; res = res->ai_next) {
void *addr;
NSString *ipver = @"";
char ipstr[INET6_ADDRSTRLEN];

if (res->ai_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;

addr = &(ipv4->sin_addr);
ipver = @"IPv4";
} else if (res->ai_family == AF_INET6){
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_<pre name="code" class="objc">addr;
addr = &(ipv6->sin6_addr);
ipver = @"IPv6";
} else {
continue; }

inet_ntop(res->ai_family, addr, ipstr,sizeof ipstr);
NSLog(@"     %@  %s", ipver, ipstr);
AddrInfo *ai2 = [[AddrInfo alloc] init];
[ai2 getNameWithSockaddr:res->ai_addr];
if (ai2.errorCode ==0)
NSLog(@"--%@ %@",ai2.hostname, ai2.service);
}
freeaddrinfo(results);


CFNetwork的方法感觉更加复杂,真是找虐啊

主要步骤(CFNetwork部分)

Hostname转换为IP地址
1.使用给定的hostname,利用CFHostCresteWithName创建CFHostRef
2.使用CFHostStartInfoResolution对hostRef进行分解
3.使用CFHostGetAddress取得地址(返回值是数组CFArrayRef),CFArrayGetCount取得地址数组的个数
4.然后使用CFDataGetBytePtr将地址数组中每个数返回为sockaddr struct,再利用getnameinfo()得到ipaddr

Address返回Hostname
1.给定的address,使用getaddrinfo返回addrinfo struct --results
2.使用results中的ai_addr 和 ai_addrlen, 以及CFDataCreate返回CFDataRef
3.CFHostCresteWithAddress创建CFHostRef
4.分解
5.CFHostNames取得名字
6.这个名字数组直接能用






                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Network socket