網(wǎng)絡通信的要素
- socket
- 通過socket來建立連接,然后通信
- IP -- Internet Protocol
- 網(wǎng)絡上主機設備的唯一標識
- 端口號
- 不同進程的標識
- 傳輸協(xié)議
- 通訊規(guī)則
Socket
- 套接字
- 網(wǎng)絡上的兩個程序通過一個
雙向的通信連接
實現(xiàn)數(shù)據(jù)的交換觉鼻,這個連接的一端稱為一個socket湿滓。 - 應用程序通常通過"套接字"向網(wǎng)絡發(fā)出請求或者應答網(wǎng)絡請求
傳輸協(xié)議
常用的傳輸協(xié)議有TCP和UDP
-
TCP-Transmission Control Protocol:(傳輸控制協(xié)議)
- 建立連接芹壕,形成數(shù)據(jù)傳輸?shù)耐ǖ?/li>
- 可以進行大數(shù)據(jù)的傳輸畏梆,傳輸數(shù)據(jù)大小不受限制
- 通過
三次握手
完成連接,是可靠
協(xié)議痕惋,安全的站故,但同時也是效率低
的
-
UDP-User Datagram Protocol:(用戶數(shù)據(jù)協(xié)議)
- 將數(shù)據(jù)以及源和目的封裝成數(shù)據(jù)包,不需要建立連接
- 數(shù)據(jù)包大小限制在64K之內(nèi)
- 因為無需連接皆怕,所以是
不可靠
的數(shù)據(jù)傳輸協(xié)議,但是西篓,速度快
TCP/IP協(xié)議
- TCP/IP是個協(xié)議組愈腾,可分為三個層次:網(wǎng)絡層、傳輸層和應用層岂津。
- 在網(wǎng)絡層有IP協(xié)議虱黄、ICMP協(xié)議、ARP協(xié)議吮成、RARP協(xié)議和BOOTP協(xié)議橱乱。
- 在傳輸層中有TCP協(xié)議與UDP協(xié)議。
- 在應用層有:
- TCP包括FTP粱甫、HTTP泳叠、TELNET、SMTP等協(xié)議
- UDP包括DNS茶宵、TFTP等協(xié)議
短連接
- 連接->傳輸數(shù)據(jù)->關閉連接
- HTTP是無狀態(tài)的危纫,瀏覽器和服務器每進行一次HTTP操作,就建立一次連接乌庶,但任務結(jié)束就中斷連接种蝶。
- 短連接是指SOCKET連接后發(fā)送后
接收完
數(shù)據(jù)后馬上斷開連接。
長連接
- 連接->傳輸數(shù)據(jù)->保持連接 -> 傳輸數(shù)據(jù)-> 瞒大。螃征。。 ->關閉連接透敌。
- 長連接指建立SOCKET連接后不管是否使用都
保持連接
会傲,但安全性較差锅棕。
HTTP協(xié)議
-
數(shù)據(jù)內(nèi)容
格式
協(xié)議 - 通常拙泽,由HTTP客戶端
發(fā)起
一個請求淌山,建立
一個到服務器指定端口(默認是[80端口])的TCP
連接。HTTP服務器則在那個端口監(jiān)聽
客戶端發(fā)送過來的請求顾瞻。一旦收到請求泼疑,服務器(向客戶端)發(fā)回一個狀態(tài)行,比如"HTTP/1.1 200 OK"荷荤,和(響應的)消息退渗,消息的消息體可能是請求的文件、錯誤消息蕴纳、或者其它一些信息会油。 - 為什么HTTP使用TCP協(xié)議
- 1.保證數(shù)據(jù)的可靠
- 2.服務器的連接是有限的,所以需要斷開連接
- 3.一個網(wǎng)頁必須傳送很多數(shù)據(jù)古毛,而TCP協(xié)議提供傳輸控制翻翩,按順序組織數(shù)據(jù),和錯誤糾正
- ?HTTP格式:請求頭+請求體
- 請求頭:
- Content-Type
- Content-Length
- Accept-Language
- 請求體:請求參數(shù)
- 請求頭:
Socket 流程
Socket通信流程
代碼模擬實現(xiàn),這里使用第三方框架CocoaAsyncSocket
- 創(chuàng)建socket對象稻薇,并監(jiān)聽
// 創(chuàng)建服務監(jiān)聽對象
ServerListener *listener = [[ServerListener alloc] init];
// 開啟監(jiān)聽
[listener start];
// 開啟主運行循環(huán)來保證服務不被停止
[[NSRunLoop currentRunLoop] run];
#import "ServerListener.h"
#import "GCDAsyncSocket.h"
@interface ServerListener ()<GCDAsyncSocketDelegate>
/** socket*/
@property (nonatomic, strong) GCDAsyncSocket *socket;
@end
@implementation ServerListener
-(void)start {
// 1.創(chuàng)建socket對象
GCDAsyncSocket *socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
self.socket = socket;
NSLog(@"%@",socket);
// 2.綁定端口,端口號最好是1024以上
NSError *error = nil;
[socket acceptOnPort:5288 error:&error];
if (error) {
NSLog(@"服務開啟失敗嫂冻,有錯誤:\n%@",error);
} else {
NSLog(@"服務開啟成功");
}
}
@end
- 實現(xiàn)代理方法
#pragma mark - GCDAsyncSocket Delegate
// 有新客戶端連接時調(diào)用
-(void)socket:(GCDAsyncSocket *)serverSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket
{
// 保存客戶端socket,不然會斷開連接
[self.clientSockets addObject:clientSocket];
#warning 客戶端連接成功后,監(jiān)聽數(shù)據(jù),接收和讀取數(shù)據(jù)都是使用clientSocket
// 讀取數(shù)據(jù)
[clientSocket readDataWithTimeout:-1 tag:0];
}
// read()--讀取客戶端的數(shù)據(jù)
-(void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag
{
NSLog(@"clientSocket: HOST:%@ PORT:%@",clientSocket.connectedHost,@(clientSocket.connectedPort));
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"----\n%@",dataStr);
// 服務器響應
NSString *sendStr = @"我(服務器)收到了!H怠桨仿!\n";
NSData *sendData = [sendStr dataUsingEncoding:NSUTF8StringEncoding];
[clientSocket writeData:sendData withTimeout:-1 tag:0];
// 每次讀取完數(shù)據(jù)后,還得監(jiān)聽數(shù)據(jù)
[clientSocket readDataWithTimeout:-1 tag:0];
}
// write()--數(shù)據(jù)發(fā)送成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(@"%s",__func__);
}