一、 Socket介紹
來由:多個TCP連接或多個應用程序進程可能需要通過同一個TCP協(xié)議端口傳輸數(shù)據(jù)夸溶。為了區(qū)別不同的應用程序進程和連接缝裁,計算機操作系統(tǒng)為應用程序與TCP/IP協(xié)議交互提供了套接字(Socket)接口。應用層可以和傳輸層通過Socket接口氢妈,區(qū)分來自不同應用程序進程或網(wǎng)絡連接的通信段多,實現(xiàn)數(shù)據(jù)傳輸?shù)牟l(fā)服務。
Socket又稱為“套接字”加缘,是系統(tǒng)提供的用于網(wǎng)絡通信的方法生百。Socket是對TCP/IP協(xié)議的封裝柄延,Socket本身并不是協(xié)議搜吧,而是一個調(diào)用接口(API),通過Socket摆昧,我們才能使用TCP/IP協(xié)議绅你。
建立Socket連接至少需要一對套接字昭躺,其中一個運行于客戶端领炫,稱為ClientSocket,另一個運行于服務器端似舵,稱為ServerSocket葱峡。套接字之間的連接過程分為三個步驟:服務器監(jiān)聽砰奕,客戶端請求泌参,連接確認常空。
Socket可以支持不同的傳輸層協(xié)議(TCP或UDP)漓糙,當使用TCP協(xié)議進行連接時,該Socket連接就是一個TCP連接,UDP連接同理蝗蛙。
二捡硅、Socket壮韭、TCP/IP和Http的聯(lián)系和區(qū)別
HTTP協(xié)議是基于TCP連接的纹因。
TCP/IP是傳輸層協(xié)議瞭恰,主要解決數(shù)據(jù)如何在網(wǎng)絡中傳輸惊畏;
而HTTP是應用層協(xié)議,主要解決如何包裝數(shù)據(jù)偷俭。
在傳輸數(shù)據(jù)時候可以只是用TCP/IP,但是這樣沒有應用層乳规,無法識別傳輸?shù)臄?shù)據(jù)類容合呐,這樣是沒有意義的淌实,如果想使傳輸?shù)臄?shù)據(jù)有意義,則必須使用應用層協(xié)議恨闪,HTTP就是一種咙咽,WEB使用它封裝HTTP文本信息,然后使用TCP/IP協(xié)議傳輸?shù)骄W(wǎng)絡上蜡豹。
Socket是應用層與TCP/IP協(xié)議族通信的中間軟件抽象層溉苛,是它的一組接口愚战。通過Socket凤巨,我們才能使用TCP/IP協(xié)議。
Socket和HTTP還有一個區(qū)別是Socket一旦建立連接佑淀,服務器可以主動將數(shù)據(jù)傳輸給客戶端彰檬;而HTTP則需要客戶端先向服務器發(fā)送請求之后才能將數(shù)據(jù)返回給客戶端逢倍。但實際上Socket建立之后因為種種原因较雕,會導致斷開連接,其中一個原因就是防火墻會斷開長時間處于非活躍狀態(tài)的連接扣典,因此需要輪詢高速網(wǎng)絡贮尖,這個連接是活躍的湿硝。
(附1:網(wǎng)絡七層協(xié)議由下往上分別為物理層关斜、數(shù)據(jù)鏈路層示括、網(wǎng)絡層、傳輸層蚤吹、會話層例诀、表示層和應用層。其中物理層裁着、數(shù)據(jù)鏈路層和網(wǎng)絡層通常被稱作媒體層繁涂,是網(wǎng)絡工程師所研究的對象;傳輸層二驰、會話層扔罪、表示層和應用層則被稱作主機層,是用戶所面向和關心的內(nèi)容桶雀。)
(附2:TCP/IP五層模型的協(xié)議分為:應用層矿酵、傳輸層、網(wǎng)絡層矗积、數(shù)據(jù)鏈路層和物理層)
三辜腺、Socket在iOS中的使用
- 第三方AsyncSockets的使用
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
enum{
SocketOfflineByServer,
SocketOfflineByUser,
};
@interface SocketSingleton : NSObject<AsyncSocketDelegate>
@property (nonatomic, strong) AsyncSocket *socket; // socket
@property (nonatomic, copy ) NSString *socketHost; // socket的Host
@property (nonatomic, assign) UInt16 socketPort; // socket的prot
@property (nonatomic, retain) NSTimer *connectTimer; // 計時器
+ (SocketSingleton *)sharedInstance;
-(void)socketConnectHost;// socket連接
-(void)cutOffSocket;// 斷開socket連接
-(void)socketSendData:(NSData *) data;// socket發(fā)送數(shù)據(jù)
@end
#import "SocketSingleton.h"
@implementation SocketSingleton
+(SocketSingleton *) sharedInstance {
static SocketSingleton *sharedInstace = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace = [[self alloc] init];
});
return sharedInstace;
}
// socket連接
-(void)socketConnectHost {
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
NSError *error = nil;
BOOL isConnect = [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:-1 error:&error];;
if (isConnect) {
NSLog(@"socket連接成功");
}else {
NSLog(@"socket連接失敗");
}
}
// socket發(fā)送數(shù)據(jù)
-(void)socketSendData:(NSData *) data {
[self.socket writeData:data withTimeout:-1 tag:1];//-1不設置超時
}
// 連接成功回調(diào)
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(@"socket連接成功");
[self.socket readDataWithTimeout: -1 tag: 0];
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
[self.connectTimer fire];
}
// 心跳連接
-(void)longConnectToSocket{
// 根據(jù)服務器要求發(fā)送固定格式的數(shù)據(jù)呜投,假設為指令@"longConnect",但是一般不會是這么簡單的指令
NSData *dataStream = [@"longConnect" dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:dataStream withTimeout:-1 tag:1];//-1不設置超時
}
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *msg = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
NSDictionary *dic = @{@"message":msg};
[[NSNotificationCenter defaultCenter] postNotificationName:@"SOCKETREAGSUCCESS" object:nil userInfo:dic];
[self.socket readDataWithTimeout: -1 tag: 0];
}
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{
// [self addMessage:[NSString stringWithFormat:@"發(fā)送了"]];
}
-(void)onSocketDidDisconnect:(AsyncSocket *)sock{
NSLog(@"socket斷開連接 %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服務器掉線男图,重連
[self socketConnectHost];
}else if (sock.userData == SocketOfflineByUser) {
// 如果由用戶斷開栈戳,不進行重連
return;
}
}
// 切斷socket
-(void)cutOffSocket{
self.socket.userData = SocketOfflineByUser;
[self.connectTimer invalidate];
[self.socket disconnect];
}
@end
- 用C語言實現(xiàn)Socket
1褂痰、Socket調(diào)用庫函數(shù)主要有:
創(chuàng)建套接字
Socket(af,type,protocol)
建立地址和套接字的聯(lián)系
bind(sockid, local addr, addrlen)
服務器端偵聽客戶端的請求
listen( Sockid ,quenlen)
建立服務器/客戶端的連接 (面向連接TCP)
客戶端請求連接
Connect(sockid, destaddr, addrlen)
服務器端等待從編號為Sockid的Socket上接收客戶連接請求
newsockid=accept(Sockid谍憔,Clientaddr, paddrlen)
發(fā)送/接收數(shù)據(jù)
面向連接:
send(sockid, buff, bufflen)
面向無連接:
sendto(sockid,buff,…,addrlen)
recvfrom( )
釋放套接字
close(sockid)
四、其他
iOS中Socket編程的方式:
BSD Socket:
BSD Socket 是UNIX系統(tǒng)中通用的網(wǎng)絡接口,它不僅支持各種不同的網(wǎng)絡類型,而且也是一種內(nèi)部進程之間的通信機制汗洒。而iOS系統(tǒng)其實本質(zhì)就是UNIX憨攒,所以可以用,但是比較復雜所刀。
CFSocket:
CFSocket是蘋果提供給我們的使用Socket的方式忧吟。
AsyncSocket:
第三方開源庫煌抒,首選方式绑青,也是在開發(fā)項目中經(jīng)常會用到的。
以后有機會慢慢學習。
參考文章:iOS學習之Socket使用簡明教程- AsyncSocket
項目地址: SocketDemo