Socket(套接字)通信

網(wǎng)絡(luò)進(jìn)程間通信在傳輸層中,基本上都是用的Socket垄分,Cocoa中使用Socket有三種方式:

  1. Cocoa層:NSURL;Cocoa層是最上層的基于Objective-C的API娃磺,如URL訪問薄湿,NSStream,Bonjour偷卧,GameKit等豺瘤,大多數(shù)情況下我們常用這種API。Cocoa層是基于Core Foundation 實(shí)現(xiàn)的
  2. Core Foundation層:基于C語言的CFNetwork和CFNetServices听诸;它是蘋果對(duì)OS層的socket進(jìn)行的簡(jiǎn)單封裝坐求,以簡(jiǎn)化編程任務(wù)。該層提供了CFNetwork和CFNetServices晌梨,其中CFNetwork又是基于CFStream和CFSocket桥嗤。
  3. OS層:基于C語言的BSD socket;最底層的BSD Socket最為靈活派任,但抽象層次比較低,使用起來比較復(fù)雜璧南。

Socket 起源于Unix掌逛,是通信的基石,是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本操作單元司倚。它是網(wǎng)絡(luò)通信過程中端點(diǎn)的抽象表示豆混,包含進(jìn)行網(wǎng)絡(luò)通信必須的五種信息:連接使用的協(xié)議,本地主機(jī)的IP地址动知,本地進(jìn)程的協(xié)議端口皿伺,遠(yuǎn)地主機(jī)的IP地址,遠(yuǎn)地進(jìn)程的協(xié)議端口盒粮。
Socket是對(duì)TCP/IP協(xié)議的封裝鸵鸥,Socket本身不是協(xié)議,而是一個(gè)調(diào)用接口(API)通過Socket我們才能使用TCP/IP協(xié)議丹皱。

下面用BSD Socket基礎(chǔ)接口編程實(shí)現(xiàn)設(shè)備間的通信:

服務(wù)器端:

socket:又稱“套接字”妒穴,用于描述IP地址和端口 是一個(gè)通信鏈的句柄 可以用來實(shí)現(xiàn)不同虛擬機(jī)或不同計(jì)算機(jī)之間的通信。ServerSocket用于服務(wù)器端摊崭,Socket是建立網(wǎng)絡(luò)連接時(shí)使用的讼油。在連接成功時(shí),應(yīng)用程序兩端都會(huì)產(chǎn)生一個(gè)Socket實(shí)例呢簸,操作這個(gè)實(shí)例矮台,完成所需的會(huì)話乏屯。對(duì)于一個(gè)網(wǎng)絡(luò)連接來說,套接字是平等的瘦赫,并沒有差別辰晕,不因?yàn)樵诜?wù)器端或在客戶端而產(chǎn)生不同級(jí)別。不管是Socket還是ServerSocket它們的工作都是通過SocketImpl類及其子類完成的

  1. 創(chuàng)建Socket socket()
  2. 綁定IP地址號(hào) bind()
  3. 監(jiān)聽客戶端 listen()會(huì)阻塞當(dāng)前線程 所以應(yīng)新開辟一條線程來執(zhí)行后面操作耸彪,等待連接的建立
  4. 接收客戶端信息 accept()伞芹;
  5. 關(guān)閉socket close()

客戶端:

  1. 建立Socket
  2. 客戶端不需要綁定IP 直接創(chuàng)建connect鏈接 可以自動(dòng)獲取自身IP,服務(wù)器端IP才需要綁定蝉娜,鏈接過程中確定鏈接哪個(gè)服務(wù)器 確定服務(wù)器的IP地址 connect()
  3. 發(fā)送信息唱较,服務(wù)器端接收信息 并接收服務(wù)器端傳遞過來的信息;信息的讀取 send()
  4. 關(guān)閉Socket close()

客戶端端口應(yīng)根據(jù)服務(wù)器的端口設(shè)置召川,保持一致
*先關(guān)客戶端socket 再關(guān)服務(wù)器socket
服務(wù)器端需綁定一個(gè)IP:bind()南缓,而客戶端不用 在connect()時(shí)由系統(tǒng)隨機(jī)生成一個(gè) 。
socket()函數(shù)創(chuàng)建的socket默認(rèn)是注定類型的 荧呐,listen()函數(shù)會(huì)將傳入的socket變?yōu)楸粍?dòng)類型的汉形,等待客戶的連接要求 。

上述操作中用到的函數(shù):

  • socket ( ) 函數(shù):
    對(duì)應(yīng)于普通文件的打開操作倍阐,并返回一個(gè)文件描述字概疆;而socket()用于創(chuàng)建一個(gè)socket描述(int類型),它唯一標(biāo)識(shí)一個(gè)socket峰搪,這個(gè)socket描述字跟文件描述字一樣岔冀,后續(xù)操作(如bind、listen等都需要將該描述傳入)都有用到它概耻,將其作為參數(shù)進(jìn)行一些讀寫操作 使套。

代碼示例:

//返回的int類型值 將作為唯一的socket描述字
serverSocketId = socket(AF_INET, SOCK_STREAM, 0);
  • bind ( ) 函數(shù):
    該函數(shù)把一個(gè)地址族中的特定地址賦給socket,例如在結(jié)構(gòu)體addr中 傳入IP類型AF_INET就是把一個(gè)ipv4地址和傳入端口號(hào)組合鞠柄,賦給socket侦高。通用服務(wù)器在啟動(dòng)時(shí)會(huì)綁定一個(gè)客戶端都知道的地址用于提供服務(wù),客戶可通過它連接服務(wù)器厌杜;而客戶端由系統(tǒng)自動(dòng)分配一個(gè)端口號(hào)和本機(jī)的IP地址組合奉呛,是在connect ( ) 時(shí)由系統(tǒng)隨機(jī)生成的。
//創(chuàng)建地址結(jié)構(gòu)體
struct sockaddr_in addr;

//初始化addr結(jié)構(gòu)體
memset(&addr, 0, sizeof(addr));

//設(shè)置地址類型
addr.sin_family = AF_INET;

//設(shè)置端口號(hào)
addr.sin_port = htons(2222);

//設(shè)置ip地址    INADDR_ANY:獲取當(dāng)前本機(jī)正在使用的ip地址夯尽, htonl:統(tǒng)一成規(guī)定字節(jié)符
addr.sin_addr.s_addr = htonl(INADDR_ANY);

//綁定
int bindId = bind(serverSocketId, (struct sockaddr*)&addr, sizeof(addr));
  • listen ( ) 侧馅、connect ( ) 函數(shù):
    如果作為一個(gè)服務(wù)器,在調(diào)用socket ( ) 呐萌、bind ( ) 之后就會(huì)調(diào)用listen ( ) 來監(jiān)聽這個(gè)socket馁痴,如果客戶端這時(shí)調(diào)用connect ( ) 發(fā)出連接請(qǐng)求,服務(wù)器端就會(huì)接收到這個(gè)請(qǐng)求肺孤。listen函數(shù)會(huì)將socket變?yōu)楸粍?dòng)類型罗晕,等待客戶的連接請(qǐng)求济欢。客戶端通過調(diào)用connect函數(shù)來建立與TCP服務(wù)器的連接小渊。
//監(jiān)聽   
int listenId = listen(serverSocketId, 5);

//創(chuàng)建服務(wù)器端addr地址
struct sockaddr_in addr;

//初始化addr
memset(&addr, 0, sizeof(addr));

//IP地址類型
addr.sin_family = AF_INET;

//設(shè)置端口號(hào)
addr.sin_port = htons(2222);

//設(shè)置指定的ip地址
inet_pton(AF_INET, "192.168.1.103", &addr.sin_addr);

//連接
int connectId = connect(clientSocketId, (struct sockaddr*)&addr,sizeof(addr));
  • accept ( ) 函數(shù):
    TCP客戶端調(diào)用connect函數(shù)之后就向TCP服務(wù)器發(fā)送了一個(gè)連接請(qǐng)求法褥,TCP服務(wù)器監(jiān)聽到這個(gè)請(qǐng)求之后就會(huì)調(diào)用accept ( ) 函數(shù)接受請(qǐng)求,這樣連接就建立完成酬屉,之后可以開始網(wǎng)絡(luò)I/O操作半等,類同于普通文件de讀寫I/O操作。
    注意:accept函數(shù)的第一個(gè)參數(shù)為服務(wù)器的socket描述字呐萨,是服務(wù)器開始調(diào)用socket函數(shù)生成的 稱為監(jiān)聽socket描述字杀饵;而通過accept函數(shù)返回的是已連接的socket描述字,一個(gè)服務(wù)器通常僅創(chuàng)建一個(gè)監(jiān)聽socket描述字谬擦,它在該服務(wù)器的生命周期內(nèi)一直存在切距。內(nèi)核為每一個(gè)由服務(wù)器進(jìn)程接收的客戶連接創(chuàng)建了一個(gè)已連接socket描述字(即accept函數(shù)返回的socket描述字),當(dāng)服務(wù)器完成了對(duì)某個(gè)客戶的服務(wù)惨远,相應(yīng)的已連接socket描述字就被關(guān)閉谜悟。
//返回值是由內(nèi)核自動(dòng)生成的一個(gè)全新的描述字,代表與返回客戶的連接
socketNewId = accept(serverSocketId, NULL, NULL);
  • 網(wǎng)絡(luò) I/O 操作函數(shù)組:服務(wù)器端與客戶端連接完成后北秽,就可調(diào)用網(wǎng)絡(luò) I/O進(jìn)行需要的操作了 主要有以下幾組:
    read ( ) / write ( ) 葡幸;recv ( ) / send ( ) ;readv ( ) / writev ( ) 贺氓;recvmsg ( ) / sendmsg ( ) 蔚叨;recvfrom ( ) / sendto ( )

*write函數(shù)負(fù)責(zé)從fd中讀取內(nèi)容,讀取成功時(shí)掠归,read返回實(shí)際所讀的字節(jié)數(shù)缅叠,如果返回的值是0 表示已經(jīng)讀到文件的結(jié)束了悄泥,小于0表示出現(xiàn)了錯(cuò)誤虏冻。如果錯(cuò)誤為EINTR說明讀是由中斷引起的,如果是ECONNREST表示網(wǎng)絡(luò)連接出了問題弹囚。
*write函數(shù)將but中的那邊有特色子節(jié)內(nèi)容寫入文件描述符fd厨相,成功時(shí)返回寫的字節(jié)數(shù),失敗時(shí)返回-1鸥鹉,并設(shè)置error變量蛮穿。在網(wǎng)絡(luò)程序中 當(dāng)我們向套接字文件描述符write時(shí)有兩種可能:(1)write的返回值大于0,表示write了部分或者全部的數(shù)據(jù)(2)返回的值小于0毁渗,此時(shí)出現(xiàn)了錯(cuò)誤践磅。如果錯(cuò)誤為EINTR,表示在write的時(shí)候出現(xiàn)了中斷錯(cuò)誤灸异,如果為EPIPE表示網(wǎng)絡(luò)連接出現(xiàn)問題(可能對(duì)方已經(jīng)關(guān)閉了連接)

我們用代碼演示其中的 recv ( ) / send ( ) 函數(shù)組 :

//開辟空間
char str[1000];

//接收信息
long recvId = recv(socketNewId, &str, 1000, 0);    
char *str = "hehe";

//發(fā)送消息
long sendid = send(clientSocketId, str, sizeof(str), 0);
  • close ( ) 函數(shù):
    在服務(wù)器與客戶端建立連接之后會(huì)進(jìn)行一些操作府适,完成操作后就要關(guān)閉相應(yīng)的socket描述字羔飞,好比操作完打開的文件要調(diào)用fclose關(guān)閉打開的文件。close一個(gè)TCP socket時(shí)就把該socket標(biāo)記為關(guān)閉檐春,然后立即返回到調(diào)用進(jìn)程逻淌。該描述字不能再由調(diào)用進(jìn)程使用,即不能再作為read或write的第一個(gè)參數(shù)疟暖。
    注意:close操作只是使相應(yīng)的socket描述字的引用計(jì)數(shù)-1卡儒,而只有當(dāng)其引用計(jì)數(shù)為0時(shí)才會(huì)觸發(fā)TCP客戶端向服務(wù)器端向服務(wù)器發(fā)送終止連接請(qǐng)求。
close(socketNewId);
close(serverSocketId);

socket中TCP的三次握手建立連接:

當(dāng)客戶端調(diào)用connect時(shí)俐巴,觸發(fā)了連接請(qǐng)求骨望,向服務(wù)器發(fā)送了SYNJ包,這時(shí)connect進(jìn)入阻塞狀態(tài)窜骄;服務(wù)器監(jiān)聽到連接請(qǐng)求(收到SYNJ包)調(diào)用accept函數(shù)接收請(qǐng)求向客戶端發(fā)送SYNK锦募,ACKJ+1,這時(shí)accept進(jìn)入阻塞狀態(tài)邻遏;客戶端收到服務(wù)器的SYNK糠亩,ACKJ+1之后,這時(shí)connect返回准验,并對(duì)SYNK進(jìn)行確認(rèn)赎线;服務(wù)器收到ACKK+1時(shí),accept返回糊饱,至此三次握手完畢垂寥,連接建立×矸妫客戶端的connect在三次握手的第二次返回滞项,而服務(wù)器端的accept在三次握手的第三次返回

socket中TCP的四次握手釋放連接:

某個(gè)應(yīng)用進(jìn)程首先調(diào)用close主動(dòng)關(guān)閉連接,這時(shí)TCP發(fā)生一個(gè)FIN M夭坪;另一個(gè)端接收到FIN M之后執(zhí)行被動(dòng)關(guān)閉文判,對(duì)這個(gè)FIN進(jìn)行確認(rèn)。它的接收也作為文件結(jié)束符傳遞給應(yīng)用進(jìn)程室梅,因?yàn)镕IN的接受意味著應(yīng)用程序在相應(yīng)的連接上再也接收不到額外數(shù)據(jù)戏仓;一段時(shí)間后,接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用close關(guān)閉它的socket亡鼠,這導(dǎo)致它的TCP也發(fā)送一個(gè)FINN赏殃;接收到這個(gè)FIN的源發(fā)送端TCP對(duì)它進(jìn)行確認(rèn)。這樣每個(gè)方向上都有一個(gè)FIN和ACK

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末间涵,一起剝皮案震驚了整個(gè)濱河市仁热,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌勾哩,老刑警劉巖抗蠢,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件根盒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡物蝙,警方通過查閱死者的電腦和手機(jī)炎滞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诬乞,“玉大人册赛,你說我怎么就攤上這事≌鸺担” “怎么了森瘪?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)票堵。 經(jīng)常有香客問我扼睬,道長(zhǎng),這世上最難降的妖魔是什么悴势? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任窗宇,我火速辦了婚禮,結(jié)果婚禮上特纤,老公的妹妹穿的比我還像新娘军俊。我一直安慰自己,他們只是感情好捧存,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布粪躬。 她就那樣靜靜地躺著,像睡著了一般昔穴。 火紅的嫁衣襯著肌膚如雪镰官。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天吗货,我揣著相機(jī)與錄音泳唠,去河邊找鬼。 笑死卿操,一個(gè)胖子當(dāng)著我的面吹牛警检,可吹牛的內(nèi)容都是我干的孙援。 我是一名探鬼主播害淤,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拓售!你這毒婦竟也來了窥摄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤础淤,失蹤者是張志新(化名)和其女友劉穎崭放,沒想到半個(gè)月后哨苛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡币砂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年建峭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片决摧。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亿蒸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掌桩,到底是詐尸還是另有隱情边锁,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布波岛,位于F島的核電站茅坛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏则拷。R本人自食惡果不足惜贡蓖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望煌茬。 院中可真熱鬧摩梧,春花似錦、人聲如沸宣旱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浑吟。三九已至笙纤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間组力,已是汗流浹背省容。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留燎字,地道東北人腥椒。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親边翁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子塘匣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 一、網(wǎng)絡(luò)各個(gè)協(xié)議:TCP/IP滨砍、SOCKET、HTTP等 網(wǎng)絡(luò)七層由下往上分別為物理層、數(shù)據(jù)鏈路層惋戏、網(wǎng)絡(luò)層领追、傳輸層...
    杯水救車薪閱讀 2,258評(píng)論 0 17
  • 1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)响逢、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)绒窑、lso...
    北辰青閱讀 9,398評(píng)論 0 11
  • 前言 我們深諳信息交流的價(jià)值,那網(wǎng)絡(luò)中進(jìn)程之間如何通信舔亭,如我們每天打開瀏覽器瀏覽網(wǎng)頁(yè)時(shí)回论,瀏覽器的進(jìn)程怎么與web服...
    Chars閱讀 2,972評(píng)論 2 117
  • 1)OSI與TCP/IP各層的結(jié)構(gòu)與功能谱净,都有哪些協(xié)議。 OSI分層 (7層):物理層擅威、數(shù)據(jù)鏈路層壕探、網(wǎng)絡(luò)層、傳輸層...
    ldlywt閱讀 2,306評(píng)論 0 26
  • 秋色 從來沒有這么仔細(xì)地觀察秋色郊丛±钋耄看這銀杏,大部分已變金黃厉熟,...
    拙蘭閱讀 666評(píng)論 11 16