Socket是什么?
要了解什么是 Socket,首先需要了解 TCP/IP、UDP!?
TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協(xié)議/網(wǎng)間協(xié)議脚作,是一個(gè)工業(yè)標(biāo)準(zhǔn)的協(xié)議集晋南,它是為廣域網(wǎng)(WANs)設(shè)計(jì)的贞铣。
UDP(User Data Protocol幅骄,用戶數(shù)據(jù)報(bào)協(xié)議)是與TCP相對(duì)應(yīng)的協(xié)議展哭。它是屬于TCP/IP協(xié)議族中的一種。
TCP/IP協(xié)議族包括運(yùn)輸層聪铺、網(wǎng)絡(luò)層化焕、鏈路層。現(xiàn)在你知道TCP/IP與UDP的關(guān)系了吧铃剔。
如果大家對(duì)于 七層協(xié)議模型 不是非常了解的話,你可以,沉下心來(lái)看看下面這張圖:
那么TCP/IP、UDP和socket又有什么關(guān)系呢???
Socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層查刻,它是一組接口键兜。在設(shè)計(jì)模式中,Socket其實(shí)就是一個(gè)門(mén)面模式穗泵,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面普气,對(duì)用戶來(lái)說(shuō),一組簡(jiǎn)單的接口就是全部佃延,讓Socket去組織數(shù)據(jù)现诀,以符合指定的協(xié)議。
Socket怎么用
這里其實(shí)還有很多網(wǎng)絡(luò)相關(guān)的知識(shí)需要科普,但是篇幅有限,如果靚仔靚女的你對(duì)于這一塊有點(diǎn)陌生,你可以買(mǎi)一些網(wǎng)絡(luò)相關(guān)的書(shū)籍
《TCP/IP詳解 卷1:協(xié)議》
《圖解HTTP》
《Unix網(wǎng)絡(luò)編程》
HTTPS權(quán)威指南
Socket 作為一套接口,那么是怎么用的呢? 下面一圖勝前言:?
Socket 傳輸?shù)奶攸c(diǎn):
1: 傳輸數(shù)據(jù)為字節(jié)級(jí)履肃,傳輸數(shù)據(jù)可自定義仔沿,數(shù)據(jù)量小(對(duì)于手機(jī)應(yīng)用講:費(fèi)用低)
2: 傳輸數(shù)據(jù)時(shí)間短尺棋,性能高
3: 適合于客戶端和服務(wù)器端之間信息實(shí)時(shí)交互
4: 可以加密,數(shù)據(jù)安全性強(qiáng)
正因?yàn)檫@些優(yōu)勢(shì),常被用來(lái)做即時(shí)通訊重要媒介
上圖就是通過(guò) socket 在客戶端和終端做的來(lái)回通訊
socket使用代碼實(shí)現(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;}
(滑動(dòng)顯示更多)
domain:協(xié)議域封锉,又稱協(xié)議族(family)。常用的協(xié)議族有AF_INET膘螟、AF_INET6成福、AF_LOCAL(或稱AF_UNIX,Unix域Socket)荆残、AF_ROUTE等奴艾。協(xié)議族決定了socket的地址類(lèi)型,在通信中必須采用對(duì)應(yīng)的地址内斯,如AF_INET決定了要用ipv4地址(32位的)與端口號(hào)(16位的)的組合蕴潦、AF_UNIX決定了要用一個(gè)絕對(duì)路徑名作為地址。
type:指定Socket類(lèi)型嘿期。常用的socket類(lèi)型有SOCK_STREAM品擎、SOCK_DGRAM、SOCK_RAW备徐、SOCK_PACKET萄传、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一種面向連接的Socket,針對(duì)于面向連接的TCP服務(wù)應(yīng)用秀菱。數(shù)據(jù)報(bào)式Socket(SOCK_DGRAM)是一種無(wú)連接的Socket振诬,對(duì)應(yīng)于無(wú)連接的UDP服務(wù)應(yīng)用。
protocol:指定協(xié)議衍菱。常用協(xié)議有IPPROTO_TCP赶么、IPPROTO_UDP、IPPROTO_STCP脊串、IPPROTO_TIPC等辫呻,分別對(duì)應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議琼锋、STCP傳輸協(xié)議放闺、TIPC傳輸協(xié)議。
注意:1.type和protocol不可以隨意組合缕坎,如SOCK_STREAM不可以跟IPPROTO_UDP組合怖侦。當(dāng)?shù)谌齻€(gè)參數(shù)為0時(shí),會(huì)自動(dòng)選擇第二個(gè)參數(shù)類(lèi)型對(duì)應(yīng)的默認(rèn)協(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(@"鏈接成功");
(滑動(dòng)顯示更多)
參數(shù)一:套接字描述符
參數(shù)二:指向數(shù)據(jù)結(jié)構(gòu)sockaddr的指針,其中包括目的端口和IP地址
參數(shù)三:參數(shù)二sockaddr的長(zhǎng)度荷腊,可以通過(guò)sizeof(struct sockaddr)獲得
返回值: 成功則返回0艳悔,失敗返回非0,錯(cuò)誤碼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;
(滑動(dòng)顯示更多)
__uint8_t sin_len;假如沒(méi)有這個(gè)成員很钓,其所占的一個(gè)字節(jié)被并入到sin_family成員中
sa_family_t sin_family;??一般來(lái)說(shuō)AF_INET(地址族)PF_INET(協(xié)議族)
in_port_t sin_port;?// 端口
struct in_addr sin_addr;//?ip
char sin_zero[8];沒(méi)有實(shí)際意義,只是為了 跟SOCKADDR結(jié)構(gòu)在內(nèi)存中對(duì)齊
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?=?@"";
(滑動(dòng)顯示更多)
s:一個(gè)用于標(biāo)識(shí)已連接套接口的描述字。
buf:包含待發(fā)送數(shù)據(jù)的緩沖區(qū)董栽。
len:緩沖區(qū)中數(shù)據(jù)的長(zhǎng)度码倦。
flags:調(diào)用執(zhí)行方式。
返回值: 如果成功锭碳,則返回發(fā)送的字節(jié)數(shù)袁稽,失敗則返回SOCKET_ERROR.一個(gè)中文對(duì)應(yīng) 3 個(gè)字節(jié)!UTF8?編碼擒抛!
4: 接受消息
while (1) {? ? uint8_t buffer[1024];? ? ssize_t recvLen = recv(self.clinenId, buffer, sizeof(buffer), 0);? ? if (recvLen == 0) {? ? ? ? NSLog(@"接收到了0個(gè)字節(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 = @"";? ? });}
(滑動(dòng)顯示更多)
參數(shù)一: 客戶端socket
參數(shù)二: 接收內(nèi)容緩沖區(qū)地址
參數(shù)三: 接收內(nèi)容緩存區(qū)長(zhǎng)度
參數(shù)四: 接收方式推汽,0表示阻塞,必須等待服務(wù)器返回?cái)?shù)據(jù)
返回值:如果成功歧沪,則返回讀入的字節(jié)數(shù)歹撒,失敗則返回SOCKET_ERROR
Socket 總結(jié)
Socket 的使用還是非常簡(jiǎn)單的! 對(duì)于iOS開(kāi)發(fā)有點(diǎn)吃力的原因是在于:
都是C函數(shù)
函數(shù)參數(shù)多并且陌生
網(wǎng)絡(luò)這一塊知識(shí)的盲區(qū)