zoukankan      html  css  js  c++  java
  • socket网络间通信初识


    NSOperation:
    1. 指定同一时间最大执行的操作数
    queue.max……
    2. 设定队列中的任务时间的依赖关系
    task1 依赖于 task2: task2 —> task1
    3. 回到主线程(找到如何获取主队列的方式)[NSOperation mainQueue]:

    keyword: iOS main queue

    Socket: 网络中的两个程序通过双向的通讯,达到交换数据的目的。

    发送(客户端):终端控制台
    接收(服务器端):  终端控制台(sever.py)

    资源:网页(www.sina.com.cn)/图片/软件/.......

    1. 服务器监听状态 standby (开机+应用程序启动)
    2. 客户端发送请求Request给服务器端
    3. 连接确认, 客户端接收服务器返回的数据

    客户端:iOS应用程序

    服务器端:启动server.py

    #coding:utf-8
    
    from twisted.internet.protocol import Factory, Protocol
    from twisted.internet import reactor
    
    class IphoneChat(Protocol):
        def connectionMade(self):
            self.factory.clients.append(self)
            print "当前连线的客户端有", self.factory.clients
    
        def connectionLost(self, reason):
            self.factory.clients.remove(self)
    
        def dataReceived(self, data):
            a = data.split(':')
            if len(a) > 1:
                command = a[0].strip()
                content = a[1].strip()
    
                msg = ""
                if command == "iam":
                    self.name = content
                    msg = self.name + " 加入了聊天室"
    
                elif command == "msg":
                    msg = self.name + ": " + content
    
                print msg
    
                for c in self.factory.clients:
                    c.message(msg)
    
        def message(self, message):
            self.transport.write(message + '\n')
    
    
    factory = Factory()
    factory.clients = []
    factory.protocol = IphoneChat
    reactor.listenTCP(1025, factory)
    print "Iphone Chat server started"
    reactor.run()
    脚本代码


    NSInputStream:    读取数据
    NSOutputStream:写数据


    发送消息:
    功能:
    存放接收消息 —> NSArray —> UITableView

    准备工作:
    UITableView准备(datasource, delegate)
    两个stream的delegate (NSStreamDelegate)

    具体实现:

    @interface ViewController () <UITableViewDataSource, UITableViewDelegate, NSStreamDelegate>
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (weak, nonatomic) IBOutlet UITextField *messageTextField;
    
    //输入流(读)
    @property (nonatomic, strong) NSInputStream *inputStream;
    
    //输出流(写)
    @property (nonatomic, strong) NSOutputStream *outputStream;
    
    //存放服务器返回消息的可变数组
    @property (nonatomic, strong) NSMutableArray *messageArray;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //初始化可变数组对象
        self.messageArray = [NSMutableArray array];
        
        //设置delegate
        self.tableView.dataSource = self;
        self.tableView.delegate = self;
        
        //准备工作:和服务器端进行连接
        [self createConnectionToServer];
    
    }
    
    - (void)createConnectionToServer {
        //telnet 196.112.122.11 1025
        
        //创建两个stream相关的类
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        
        //NSStream不具有连接服务器的功能
        //创建和服务器的连接
        /**
         第二个参数:连接服务器的ip地址 (localhost)
         第三个参数:指定端口
         */
        CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"localhost", 1025, &readStream, &writeStream);
        
        //将底层的CFStream转换成NSStream相关的类
        self.inputStream = (__bridge NSInputStream *)readStream;
        self.outputStream = (__bridge NSOutputStream *)writeStream;
        
        //设置两个stream的delegate
        self.inputStream.delegate = self;
        self.outputStream.delegate = self;
        
        //把这两个stream添加到runloop中(原因:才可以响应对应的代理方法)
        [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        
        //将两个stream打开
        [self.inputStream open];
        [self.outputStream open];
    }
    
    - (IBAction)enterChatRoom:(id)sender {
        //iam:xxxxx
        NSString *text = @"iam:Maggie";
        
        //NSString --> NSData
        NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
        
        //写数据(OutputSteam)
        [self.outputStream write:[data bytes] maxLength:[data length]];
    }
    
    - (IBAction)sendMessage:(id)sender {
        //发送消息到服务器端(msg:xxxxx)
        NSString *messageStr = [NSString stringWithFormat:@"msg:%@", self.messageTextField.text];
        
        //往outputStream中写数据
        NSData *data = [messageStr dataUsingEncoding:NSUTF8StringEncoding];
        [self.outputStream write:[data bytes] maxLength:[data length]];
        
        //清空textField文本
        self.messageTextField.text = nil;
    }
    
    
    #pragma mark -- NSStreamDelegate
    //针对两个管道Stream, 处理不同的事件
    - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
        switch (eventCode) {
            case NSStreamEventOpenCompleted:
                NSLog(@"Stream打开");
                break;
            case NSStreamEventHasSpaceAvailable:
                NSLog(@"Stream还有空间可以放数据");
                break;
            case NSStreamEventHasBytesAvailable:
                NSLog(@"此时Stream有数据");
                [self readBytes:aStream];
                break;
            case NSStreamEventErrorOccurred:
                NSLog(@"有错误出现");
                //把stream关掉
                [self.inputStream close];
                [self.outputStream close];
                //从runloop中移除
                [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                break;
                
            default:
                break;
        }
        
    }
    
    - (void)readBytes:(NSStream *)aStream {
        //将数据显示在table view上
        //首先判定是服务器返回的(将服务器消息显示在table view上)
        if (aStream == self.inputStream) {
            unsigned char readData[1024];
            //读取输入流的数据(服务器返回来的数据)
            while ([self.inputStream hasBytesAvailable]) {
                //获取服务器返回的数据
                /**
                 第一个参数:读取的数据存放对象
                 第二个参数:读取的最大bytes数量
                 */
                NSInteger length = [self.inputStream read:readData maxLength:sizeof(readData)];
                if (length > 0) {
                    //读取到数据
                    NSString *messageStr = [[NSString alloc] initWithBytes:readData length:length encoding:NSUTF8StringEncoding];
                    //将获取到的字符串添加到可变数组中
                    [self.messageArray addObject:messageStr];
                    //显示在table view上
                    [self.tableView reloadData];
                    
                }
            }
        }
    }
    
    #pragma mark -- table view datasouce/delegate
    - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.messageArray.count;
    }
    
    //设置cell
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        //创建identifier
        static NSString *cellID = @"messageCell";
        
        //从缓存池中获取cell(Reuse可复用性)
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
        
        //如果缓存池中没有,再重新创建
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
        }
        
        //设置cell文本属性
        cell.textLabel.text = self.messageArray[indexPath.row];
        
        return cell;
    }
    
    @end

    练习:
    1. 点中UITextFiled,键盘弹出,table view和其他控件上移
    2. 让table view最后一行,始终显示用户发送的最新的消息



    官方socket实例代码链接:
    https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/Streams/Articles/NetworkStreams.html#//apple_ref/doc/uid/20002277-BCIDFCDI


    URL: (Uniform Resource Locator) 统⼀资源定位符
    最完整格式:
    协议://IP地址:端口/路径/文件名字
    一般格式:
    IP地址(域名)/路径/文件名字

    协议的通俗说法:发送数据方和接收数据方规定的传送数据的规则

    File协议:从本地查找相应的文件
    URL —>
    file:///Users/tarena/Downloads/testImages/aa.jpg

    HTTP协议内部数据

    小例子:
    把本地mac机器改装成提供web服务(Apache软件)的服务器步骤:
    1. 查看Apache软件是否安装
    sudo apachectl -v
    输入mac系统的密码
    2. 启动apache软件
    sudo apachectl start
    3. 在浏览器中输入localhost,显示It works!就表示mac机器成为了可以提供网页服务的机器

    http://IP地址:端口/路径/文件名字


    MIME: 客户端(浏览器)指定服务器返回的类型(xxx.html)
    文本类型:
    text/html:不仅包含文本,也包含.jpg/.gif/.....
    text/xml
    text/plain: 只能包含文本

    http协议的规则:
    1. 指定MIME类型: text/html
    2. 方法:
        a. GET (获取资源:html文件)
        b. DELETE (删除资源:图片)
        c. POST: 登录(用户名/密码)
        d. PUT: 上传文件/上传信息
    3. status code: 服务返回的状态码
         a. 成功:200/OK
         c. 失败:
         404 -> 未找到资源(html文件)
         400 -> 客户端的请求,服务器端无法解析
         501 -> 服务器错误
    4.响应Response (服务器返回):
    content-length: 总长度多少
    content-range (****): 默认服务器会返回客户端请求的资源的总数据



    iOS中发送网络请求的方案:
    方案一:
    NSURLConnection (相对麻烦/更加理解http原理):
    方案二
    NSURLSession (简单/封装性高):

    此案例主要以方案一来实现:
    样例:界面上输入任意一个网址(URL), 将返回的网页显示到界面上(xxx.html) (NSURLConnection)
    UI界面:UITextField; UIButton; UIWebView(内嵌浏览器)

    具体实现:

    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIWebView *webView;
    @property (weak, nonatomic) IBOutlet UITextField *urlTextField;
    
    //界面输入的URL
    @property (nonatomic, strong) NSURL *url;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
    }
    //发送请求Request ---> 接收响应Response
    - (IBAction)sendSyncRequest:(id)sender {
        //NSURLConnection
        //1.创建一个客户端发送请求对象
        self.url = [NSURL URLWithString:self.urlTextField.text];
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:self.url];
        //2.开始执行发送的同步请求
        //3.获取服务器返回的html文件
        NSError *error = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&error];
        if (error) {
            NSLog(@"发送请求失败:%@", error.userInfo);
            return;
        }
        
        //4.并显示在UIWebView上
        [self.webView loadData:data
                      MIMEType:@"text/html"
              textEncodingName:@"utf-8"
                       baseURL:nil];
        
        NSLog(@"请求执行完毕%@; 数据的大小%lu", [NSThread currentThread], (unsigned long)data.length);
    }
    
    
    - (IBAction)sendAsyncRequest:(id)sender {
        
        //1.创建客户端发送请求对象
        self.url = [NSURL URLWithString:self.urlTextField.text];
        NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
        
        //2.异步执行请求
        //创建非主队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            //获取response的状态码(判定服务器是否返回成功200)
            //data:服务器返回的数据
            //connectionError:具体的错误
            NSLog(@"返回%@", [NSThread currentThread]);
            NSInteger retStatusCode = [(NSHTTPURLResponse *)response statusCode];
            if (retStatusCode == 200) {
                //回到主线程更新界面UIWebView
                dispatch_async(dispatch_get_main_queue(), ^{
                    //3.显示服务器返回的数据到UIWebView
                    [self.webView loadData:data MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:nil];
                });
            } else {
                NSLog(@"失败%@",connectionError.userInfo);
            }
        }];    
    }
    
    @end
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 阮小二买彩票
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
    让程序后台隐藏运行
    只要你喜欢,并且可以养家糊口,就是好的
  • 原文地址:https://www.cnblogs.com/YKiOS/p/4802366.html
Copyright © 2011-2022 走看看