iOS网络编程

来源:互联网 发布:php 提示非法字符串 编辑:程序博客网 时间:2024/06/07 23:03

没想到CSDN的两种编辑器不能进行同篇文章的切换!只能再整理一下了
1 . 使用CFNetwork(精简模式)

  • 定义一个URL 使用NSRUL创建一个url

  • 使用NSURLRequest来创建一个请求,要将上层创建的URL作为参数传递进去。如果用NSMutableURLRequest来创建,可以修改其请求的参数

  • 创建一个NSURLConnection 在方法中需要将请求作为参数传递,并添加代理为本身 如果连接不为空则为连接成功,否则,连接不成功。

  • 代理方法:NSURLConnectionDelegate,NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // 可通过下面方法来得到编码方式/*    NSLog(@"%@",[response textEncodingName]); // 返回编码名称*/}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data // 要在其中设置编码格式,将其进行转化/*    NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF8);    NSString *str = [[NSString alloc] initWithData:data encoding:enc];*/

2 . 使用socket方式来进行网络编程
iOS网络编程层次结构也分为三层:

  • Cocoa层:NSURLBonjourGame KitWebKit
  • Core Foundation层:基于 C 的 CFNetworkCFNetServices
  • OS层:基于 C 的 BSD socket

Cocoa层是最上层的基于 Objective-C 的 API,比如 URL访问,NSStreamBonjourGameKit等,这是大多数情况下我们常用的 API。Cocoa 层是基于 Core Foundation`实现的。

Core Foundation层:因为直接使用 socket 需要更多的编程工作,所以苹果对 OS 层的 socket 进行简单的封装以简化编程任务。该层提供了 CFNetworkCFNetServices,其中 CFNetwork 又是基于 CFStreamCFSocket

OS层:最底层的 BSD socket 提供了对网络编程最大程度的控制,但是编程工作也是最多的。因此,苹果建议我们使用 Core Foundation 及以上层的 API 进行编程。

本文将介绍如何在 iOS 系统下使用最底层的 socket 进行编程,这和在 window 系统下使用 C/C++ 进行 socket 编程并无多大区别。

BSD socket ARI简介
接口详解:

  • int socket(int addressFamily, int type, int protocol)

socket创建并初始化socket,返回该socket的文件描述符,如果描述符为-1表示创建失败。
通常参数addressFamilyIPv4(AF_INET)IPv6(AF_INET6)type 表示socket的类型,通常是流stream(SOCK_STREAM)或数据报文
datagram(SOCK_DGRAM)protocol参数通常设置为0,以便让系统自动选择我们合适的协议(IPPROTO_TCP),而对于datagram来说会是UDP协议(IPPROTO_UDP)。

  • int close(int socketFileDescriptor)

close关闭socket

  • int bind(int socketFileDescriptor, sockaddr *addressToBind, int
    addressStructLength)

socket与特定主机地址与端口号绑定,成功绑定返回0,失败返回-1.
成功绑定后,根据协议(TCP/UDP)的不同,我们可以对socket进行不同的操作:
UDP:因为UDP是无连接的,绑定之后就可以利用UPD socket传送数据了。
TCPTCP是需要建立端到端的连接的,为了建立TCP连接服务器必须调用listen(int socketFileDescriptor, int backlogSize)来设置服务器的缓冲区队列以接收客户端的连接请求,backlogSize表示客户端连接请求缓冲区队列的大小。当调用listen设置之后,服务器等待客户端请求,然后调用下面的accept来接受客户端的连接请求。

  • int accept(int socketFileDescriptor, sockaddr *clientAddress, int
    clientAddressSturctLength)

接受客户端连接请求并将客户端的网络地址信息保存到clientAddress中。当客户端连接请求被服务器接受之后,客户端和服务器之间的链路就建立好了,两者就可以通信了。

  • int connect(int socketFileDescriptor, sockaddr *serverAddress, int
    serverAddressLength)

客户端向特定网络地址的服务器发送连接请求,连接成功返回0,失败返回-1.
当服务器建立好之后,客户端通过调用该接口向服务器发起建立连接请求,对于 UDP来说,该接口是可选的,如果调用了该接口,表明设置了该UDP socket默认的网络地址。对TCP socket来说这就是传说中三次握手建立连接发生的地方。
注意:该接口调用会阻塞当前线程直到服务器返回。

  • hostent *gethostbyname(char *hostname)

其作用就是找到主机地址,将其作为远程主机地址传送给socketAddr,作为连接参数的一部分。
使用DNS查找特定主机名字对应的IP地址。如果找不到对应的IP地址则返回NULL

  • int send(int socketFileDescriptor, char *buffer, int bufferLength,
    int flags)

通过socket发送数据,发送成功返回成功发送的字节数,否则返回-1.
一旦连接建立好之后,就可以通过send/receive接口发送或接收数据了。注意调用connect设置了默认网络地址的UDP socket也可以调用该接口来接收数据。

  • int receive(int socketFileDescriptor, char *buffer, int bufferLength,
    int flags)

socket中读取数据,读取成功返回成功读取的字节数,否则返回-1.
一旦连接建立好后,就可以通过send/receive接口发送或接收数据了。注意调用connect设置了默认网络地址的UDP socket也可以调用该接口来发送数据。

  • int sento(int socketFileDescriptor, char *buffer, int bufferLength,
    int flags, sockaddr *destinationAddress, int
    destinationAddressLength)

通过UDP socket发送数据到特定的网络地址,发送成功返回成功发送的字节数,否则返回-1
由于UDP可以身多个网络地址发送数据,所以可以指定特定网络地址,以向其发送数据。

  • int recvfrom(int socketFileDescriptor, char *buffer, int
    bufferLength, int flags, sockaddr *fromAddress, int
    *fromAddressLength)

UDP socket中读取数据,并保存发送者的网络地址信息,读取成功返回成功读取的字节数,否则返回-1
由于UDP可以接收来自多个网络地址的数据,所以需要提供额外的参数,以保存该数据的发送者身份。

服务器工作流程:
1> 服务器调用socket(…)创建socket
2> 服务器调用listen(…)设置缓存区;
3> 服务器通过accept(…)接受客户端请求建立连接;
4> 服务器与客户端建立连接之后,就可以通过send(…)/receive(…)向客户端发送或从客户接收数据;
5> 服务器调用close关闭socket

客户端工作流程:
1> 客户端调用socket(…)创建socket;
2> 客户端调用connect(…)向服务器发起连接请求以建立连接;
3> 客户端与服务器建立连接之后,就可以通过send(…)/receive(…)向客户端发送或从客户端接收数据;
4> 客户端调用close关闭socket

客户端实例:

1> 创建socket获取文件描述符:

int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);

2> 获取远程主机的名称(需要注意 两个头文件#include <sys/socket.h> #include<netdb.h>

struct in_addr *remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];struct sockaddr_in socketParameters; // 套接字内部格式类型    socketParameters.sin_family = AF_INET; // socket internet family    socketParameters.sin_addr = *remoteInAddr; // 远程网络地址    socketParameters.sin_port = htons([port intValue]); // 远程网络地址端口 htons的就是host to net short的意思,这个函数就是把以电脑上数据存储顺序的无符号短整型数转换成以网络上的数据存储顺序的短整型数

3> 与服务器进行socket连接,需要传入socket参数

int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));

4> 接收服务器发送来的数据 返回值大于0则表示为成功

int result = recv(socketFileDescriptor, &buffer, length, 0);

5> 关闭socket

close(socketFileDescriptor);

代码整体为:

 NSString *host = [url host];    NSNumber *port = [url port];// 创建Socket    // creat socket    int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);    if (socketFileDescriptor == -1) {        NSLog(@"fail to create socket");        return;    }// 获取远程主机的名称    // get ip address from host    struct hostent *remoteHostEnt = gethostbyname([host UTF8String]);    if (NULL == remoteHostEnt) {        close(socketFileDescriptor);        [self networkFailedWithErrorMessage:@":Unable to resolve the hostname of warehouse server."];        return;    }// 取得远程主机的IP地址    struct in_addr *remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];    // set the socket parameters    struct sockaddr_in socketParameters; // 套接字内部格式类型    socketParameters.sin_family = AF_INET; // socket internet family    socketParameters.sin_addr = *remoteInAddr; // 远程网络地址    socketParameters.sin_port = htons([port intValue]); // 远程网络地址端口 htons的就是host to net short的意思,这个函数就是把以电脑上数据存储顺序的无符号短整型数转换成以网络上的数据存储顺序的短整型数// 与服务器进行socket连接 需要传入socket参数    // connect the socket sizeof(socketParameters));    int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));    if (-1 == ret) {        close(socketFileDescriptor);        NSString *errorInfo = [NSString stringWithFormat:@">> faile to connect to %@:%@",host,port];        [self networkFailedWithErrorMessage:errorInfo];        return;    }    NSLog(@">> Successfully connected to %@:%@", host, port);    NSMutableData *data  = [[NSMutableData alloc] init];    BOOL waitingForData = YES;    // continually receive data until we reach the end of the data    int maxCount = 5;    int i = 0;    while (waitingForData && i < maxCount ) {        const char *buffer[1024];        int length = sizeof(buffer);//接收到服务器发送过来的数据        // read a buffer's amount of data from the socket; the number of bytes read is returned        int result = recv(socketFileDescriptor, &buffer, length, 0);        if (result > 0) {            [data appendBytes:buffer length:length];        } else {            waitingForData = NO;        }        ++i;    }// 关闭Socket    // Close the socket    close(socketFileDescriptor);    [self networkSucceedWithData:data];
0 0
原创粉丝点击