這兩天很多學員都想聽聽關于 Socket
的內(nèi)容! 所以花了一點時間就給它備了出來,公開課分享完全足夠了!
這里通過文字形式紀錄下來,方便大家對應學習
Socket是什么?
要了解什么是 Socket
,首先需要了解 TCP/IP、UDP
! ??
TCP/IP(Transmission Control Protocol/Internet Protocol)
即傳輸控制協(xié)議/網(wǎng)間協(xié)議俩滥,是一個工業(yè)標準的協(xié)議集昌阿,它是為廣域網(wǎng)(WANs)設計的两芳。
UDP(User Data Protocol沛简,用戶數(shù)據(jù)報協(xié)議)
是與TCP相對應的協(xié)議扰藕。它是屬于TCP/IP
協(xié)議族中的一種问顷。
TCP/IP協(xié)議族
包括運輸層九府、網(wǎng)絡層稻励、鏈路層「缸瑁現(xiàn)在你知道TCP/IP與UDP的關系了吧。
如果大家對于 七層協(xié)議模型
不是非常了解的話,你可以,沉下心來看看下面???? 這張圖:
那么TCP/IP望抽、UDP
和socket
又有什么關系呢???
Socket
是應用層
與TCP/IP協(xié)議族
通信的中間軟件抽象層
加矛,它是一組接口
。在設計模式中煤篙,Socket
其實就是一個門面模式
斟览,它把復雜的TCP/IP協(xié)議族
隱藏在Socket
接口后面,對用戶來說辑奈,一組簡單的接口就是全部苛茂,讓Socket
去組織數(shù)據(jù)已烤,以符合指定的協(xié)議。
Socket怎么用
這里其實還有很多網(wǎng)絡相關的知識需要科普,但是篇幅有限,如果靚仔靚女的你對于這一塊有點陌生,你可以買一些網(wǎng)絡相關的書籍
《TCP/IP詳解 卷1:協(xié)議》
《圖解HTTP》
《Unix網(wǎng)絡編程》
HTTPS權威指南
Socket 作為一套接口,那么是怎么用的呢? 下面一圖勝前言: ??
Socket
傳輸?shù)奶攸c:
- 1: 傳輸數(shù)據(jù)為
字節(jié)級
妓羊,傳輸數(shù)據(jù)可自定義
胯究,數(shù)據(jù)量小
(對于手機應用講:費用低) - 2:
傳輸數(shù)據(jù)時間短,性能高
- 3: 適合于客戶端和服務器端之間信息實時交互
- 4: 可以加密,數(shù)據(jù)安全性強
正因為這些優(yōu)勢,常被用來做即時通訊重要媒介
上圖就是通過 socket
在客戶端和終端做的來回通訊
socket使用代碼實現(xiàn):
1: 創(chuàng)建socket
int socketID = socket(AF_INET, SOCK_STREAM, 0);
self.clinenId= socketID;
if (socketID == -1) {
NSLog(@"創(chuàng)建socket 失敗");
return;
}
-
domain
:協(xié)議域躁绸,又稱協(xié)議族(family
)裕循。常用的協(xié)議族有AF_INET
、AF_INET6
涨颜、AF_LOCAL
(或稱AF_UNIX
费韭,Unix
域Socket
)、AF_ROUTE
等庭瑰。協(xié)議族決定了socket
的地址類型星持,在通信中必須采用對應的地址,如AF_INET
決定了要用ipv4地址
(32位的)與端口號(16位的)的組合弹灭、AF_UNIX
決定了要用一個絕對路徑名作為地址督暂。 -
type
:指定Socket
類型。常用的socket
類型有SOCK_STREAM
穷吮、SOCK_DGRAM
逻翁、SOCK_RAW
、SOCK_PACKET
捡鱼、SOCK_SEQPACKET
等八回。流式Socket
(SOCK_STREAM
)是一種面向連接的Socket
,針對于面向連接的TCP服務應用驾诈。數(shù)據(jù)報式Socket
(SOCK_DGRAM
)是一種無連接的Socket
缠诅,對應于無連接的UDP
服務應用。 -
protocol
:指定協(xié)議乍迄。常用協(xié)議有IPPROTO_TCP
管引、IPPROTO_UDP
、IPPROTO_STCP
闯两、IPPROTO_TIPC
等褥伴,分別對應TCP
傳輸協(xié)議、UDP傳輸協(xié)議
漾狼、STCP
傳輸協(xié)議重慢、TIPC
傳輸協(xié)議。
注意:1.
type
和protocol
不可以隨意組合逊躁,如SOCK_STREAM
不可以跟IPPROTO_UDP
組合伤锚。當?shù)谌齻€參數(shù)為0
時,會自動選擇第二個參數(shù)類型對應的默認協(xié)議。
-
返回值
:如果調(diào)用成功就返回新創(chuàng)建的套接字的描述符屯援,如果失敗就返回INVALID_SOCKET
(Linux
下失敗返回-1
)
2: 建立連接
int result = connect(socketID, (const struct sockaddr *)&socketAddr, sizeof(socketAddr));
if (result != 0) {
NSLog(@"鏈接失敗");
return;
}
NSLog(@"鏈接成功");
-
參數(shù)一
:套接字描述符 -
參數(shù)二
:指向數(shù)據(jù)結構sockaddr
的指針猛们,其中包括目的端口和IP地址 -
參數(shù)三
:參數(shù)二sockaddr
的長度,可以通過sizeof(struct sockaddr)
獲得 -
返回值
: 成功則返回0
狞洋,失敗返回非0
弯淘,錯誤碼GetLastError()
。
struct sockaddr_in socketAddr;
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = SocketPort;
struct in_addr socketIn_addr;
socketIn_addr.s_addr = SocketIP;
socketAddr.sin_addr = socketIn_addr;
-
__uint8_t sin_len
; 假如沒有這個成員吉懊,其所占的一個字節(jié)被并入到sin_family
成員中 -
sa_family_t sin_family
; 一般來說AF_INET
(地址族)PF_INET
(協(xié)議族) -
in_port_t sin_port
; // 端口 -
struct in_addr sin_addr
; //ip
-
char sin_zero[8]
; 沒有實際意義,只是為了 跟SOCKADDR
結構在內(nèi)存中對齊
3: 發(fā)送消息
if (self.sendMsgContent_tf.text.length == 0) {
return;
}
const char *msg = self.sendMsgContent_tf.text.UTF8String;
ssize_t sendLen = send(self.clinenId, msg, strlen(msg), 0);
NSLog(@"發(fā)送 %ld 字節(jié)",sendLen);
[self showMsg:self.sendMsgContent_tf.text msgType:0];
self.sendMsgContent_tf.text = @"";
-
s
:一個用于標識已連接套接口的描述字庐橙。 -
buf
:包含待發(fā)送數(shù)據(jù)的緩沖區(qū)。 -
len
:緩沖區(qū)中數(shù)據(jù)的長度借嗽。 -
flags
:調(diào)用執(zhí)行方式态鳖。 -
返回值
: 如果成功,則返回發(fā)送的字節(jié)數(shù)恶导,失敗則返回SOCKET_ERROR
.一個中文對應3 個字節(jié)
浆竭!UTF8
編碼!
4: 接受消息
while (1) {
uint8_t buffer[1024];
ssize_t recvLen = recv(self.clinenId, buffer, sizeof(buffer), 0);
if (recvLen == 0) {
NSLog(@"接收到了0個字節(jié)");
continue;
}
// buffer -> data -> string
NSData *data = [NSData dataWithBytes:buffer length:recvLen];
NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@---%@",[NSThread currentThread],str);
dispatch_async(dispatch_get_main_queue(), ^{
[self showMsg:str msgType:1];
self.sendMsgContent_tf.text = @"";
});
}
-
參數(shù)一
: 客戶端socket
-
參數(shù)二
: 接收內(nèi)容緩沖區(qū)地址 -
參數(shù)三
: 接收內(nèi)容緩存區(qū)長度 -
參數(shù)四
: 接收方式惨寿,0表示阻塞
邦泄,必須等待服務器返回數(shù)據(jù) -
返回值
:如果成功,則返回讀入的字節(jié)數(shù)裂垦,失敗則返回SOCKET_ERROR
Socket 總結
Socket
的使用還是非常簡單的! 對于iOS開發(fā)有點吃力的原因是在于:
- 都是C函數(shù)
- 函數(shù)參數(shù)多并且陌生
- 網(wǎng)絡這一塊知識的盲區(qū)
如果想更加傻瓜式開發(fā),那么就請看下一個篇章:
CocoaAsyncSocket 關于tcp和udp 實戰(zhàn)
大師重磅內(nèi)容(17)-CocoaAsyncSocket實現(xiàn)即時通訊
大師重磅內(nèi)容(18)-CocoaAsyncSocket實現(xiàn)畫板功能