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-8from twisted.internet.protocol import Factory, Protocol from twisted.internet import reactorclass IphoneChat(Protocol):def connectionMade(self):self.factory.clients.append(self)print "當前連線的客戶端有", self.factory.clientsdef 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 = contentmsg = self.name + " 加入了聊天室"elif command == "msg":msg = self.name + ": " + contentprint msgfor 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];//設置delegateself.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的delegateself.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:xxxxxNSString *text = @"iam:Maggie";//NSString --> NSDataNSData *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 {//創建identifierstatic 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:dataMIMEType:@"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) {//回到主線程更新界面UIWebViewdispatch_async(dispatch_get_main_queue(), ^{//3.顯示服務器返回的數據到UIWebView[self.webView loadData:data MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:nil];});} else {NSLog(@"失敗%@",connectionError.userInfo);}}]; }@end?
轉載于:https://www.cnblogs.com/YKiOS/p/4802366.html
總結
以上是生活随笔為你收集整理的socket网络间通信初识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: animation的6个属性
- 下一篇: 使界面里的组件更圆滑