網(wǎng)絡(luò)編程基礎(chǔ)

(1)bind 函數(shù)如何選擇綁定地址:bind 函數(shù)的基本用法如下:

? ? ? ? ? ? ? ?? struct sockaddr_in? bindaddr;

? ? ? ? ? ? ? ?? bindaddr.sin_family?=?AF_INET;

? ? ? ? ? ? ? ?? bindaddr.sin_addr.s_addr?=?htonl(INADDR_ANY); //

? ? ? ? ? ? ? ?? bindaddr.sin_port?=?htons(3000);

? ? ? ? ? ? ? ? if?(bind(listenfd,?(struct?sockaddr?*)&bindaddr,?sizeof(bindaddr))?==?-1)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? std::cout?<<?"bind?listen?socket?error."?<<?std::endl;

? ? ? ? ? ? ? ? ? ? ? ? return?-1;

? ? ? ? ? ? ? ? }

? ? 如上所示,INADDR_ANY是一個宏,相當于地址0.0.0.0厨幻,如果應(yīng)用程序不關(guān)心bind綁定的ip地址愕掏,可以使用INADDR_ANY(如果是IPv6妇汗,則對應(yīng)in6addr_any)陋桂,這樣底層的(協(xié)議棧)服務(wù)會自動選擇

一個合適的ip地址蜓竹,這樣使在一個有多個網(wǎng)卡機器上選擇ip地址問題變得簡單耗绿。bind函數(shù)可以綁定多個可選的IP苹支,如果指定本機訪問,可設(shè)置127.0.0.1误阻,如果是局域網(wǎng)內(nèi)部訪問债蜜,設(shè)置內(nèi)網(wǎng)IP晴埂,如果是外

網(wǎng)訪問,設(shè)置0.0.0.0或?INADDR_ANY寻定。

(2)bind函數(shù)綁定端口號:如果將 bind 函數(shù)中的端口號設(shè)置成0儒洛,那么操作系統(tǒng)會隨機給程序分配一個可用的偵聽端口,windows的端口號是0~65535狼速,實際可用的更少琅锻,此外,除了服務(wù)器可以調(diào)

用bind綁定指定端口外向胡,客戶端也可以調(diào)用以指定的端口號去連接服務(wù)器恼蓬。另外,Linux 的?nc?命令有個?-p?選項(字母?p?是小寫)僵芹,這個選項的作用就是?nc?在模擬客戶端程序時处硬,可以使用指定端口

號連接到服務(wù)器程序上去,比如 命令nc?-v?-p?9999?127.0.0.1?3000 則指定9999區(qū)連接127.0.0.1 的3000端口拇派。

(3)socket的阻塞和非阻塞模式:所謂阻塞模式郁油,就當某個函數(shù)“執(zhí)行成功的條件”當前不能滿足時,該函數(shù)會阻塞當前執(zhí)行線程攀痊,程序執(zhí)行流在超時時間到達或“執(zhí)行成功的條件”滿足后恢復(fù)繼續(xù)執(zhí)

行桐腌。而非阻塞模式恰恰相反,即使某個函數(shù)的“執(zhí)行成功的條件”不當前不能滿足苟径,該函數(shù)也不會阻塞當前執(zhí)行線程案站,而是立即返回,繼續(xù)運行執(zhí)行程序流棘街。無論是 Windows 還是 Linux 平臺蟆盐,默認創(chuàng)建

的 socket 都是阻塞模式的匀哄。

? ? ? ? ? ? windows下使用ioctlsocket() 函數(shù)?將 socket 設(shè)置成非阻塞模式吻氧,ioctlsocket()?簽名如下:

? ? ? ? ? ? ? ? ? ? ? int ioctlsocket(SOCKET?s,long cmd,?u_long?*argp); ? //cmd?參數(shù)設(shè)置為?FIONBIO关斜,argp設(shè)置為0即可將 socket 設(shè)置成阻塞模式在塔,而將argp?設(shè)置成非?0?即可設(shè)置成非阻塞模式

? ? ? ? ?? linux下有三種方式可將socket設(shè)置成 非阻塞模式:

? ? ? ? ?? 1.使用?fcntl() 函數(shù)或?ioctl() 函數(shù)給創(chuàng)建的 socket 增加?O_NONBLOCK?標志來將 socket 設(shè)置成非阻塞模式:

? ? ? ? ? ? ? ? ? ?? int?oldSocketFlag?=?fcntl(sockfd,?F_GETFL,?0);

? ? ? ? ? ? ? ? ? ? int?newSocketFlag?=?oldSocketFlag?|?O_NONBLOCK;

? ? ? ? ? ? ? ? ? ? fcntl(sockfd,?F_SETFL,??newSocketFlag);

? ? ? ? ? 2.socket()?創(chuàng)建函數(shù)時直接設(shè)置非阻塞,函數(shù)簽名如:int socket(int domain,int type,int protocol);給參數(shù)type?參數(shù)增加一個?SOCK_NONBLOCK?標志即可蒸痹,如下:

? ? ? ? ? ? ? ? ? ?? int?s?=?socket(AF_INET,?SOCK_STREAM?|?SOCK_NONBLOCK,?IPPROTO_TCP);

? ? ? ?? 3.使用擴展函數(shù)?accept4()仅仆,直接將 accept 函數(shù)返回的 socket 設(shè)置成非阻塞的入篮,函數(shù)簽名:int accept4(int sockfd,?struct?sockaddr?*addr,socklen_t* addrlen,int flags); 例如:

? ? ? ? ? ? ? ? ? ? int?clientfd?=?accept4(listenfd,?&clientaddr,?&addrlen,?SOCK_NONBLOCK);

? ? ? ?? send 函數(shù)本質(zhì)上并不是往網(wǎng)絡(luò)上發(fā)送數(shù)據(jù)蛔糯,而是將應(yīng)用層發(fā)送緩沖區(qū)的數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)中去拯腮,至于什么時候數(shù)據(jù)會從網(wǎng)卡緩沖區(qū)中真正地發(fā)到網(wǎng)絡(luò)中去要根據(jù) TCP/IP 協(xié)議棧的行為來確

定,這種行為涉及到一個叫 nagel 算法和 TCP_NODELAY 的 socket 選項蚁飒。recv 函數(shù)本質(zhì)上也并不是從網(wǎng)絡(luò)上收取數(shù)據(jù)动壤,而只是將內(nèi)核緩沖區(qū)中的數(shù)據(jù)拷貝到應(yīng)用程序的緩沖區(qū)中,當然拷貝完成以

后會將內(nèi)核緩沖區(qū)中該部分數(shù)據(jù)移除淮逻。

? ? ? ? 當 socket 是阻塞模式的琼懊,繼續(xù)調(diào)用 send/recv 函數(shù)會導(dǎo)致程序阻塞在 send/recv 調(diào)用處阁簸;當 socket 是非阻塞模式,繼續(xù)調(diào)用 send/recv 函數(shù)哼丈,send/recv 函數(shù)不會阻塞程序執(zhí)行流启妹,而是會立即

出錯返回-1,我們會得到一個相關(guān)的錯誤碼削祈,Linux 平臺上該錯誤碼為 EWOULDBLOCK 或 EAGAIN(這兩個錯誤碼值相同),Windows 平臺上錯誤碼為 WSAEWOULDBLOCK脑漫。

(4)nagle算法:nagle算法的是操作系統(tǒng)網(wǎng)絡(luò)通信層的一種發(fā)送數(shù)據(jù)包機制髓抑,如果開啟,則一次放入網(wǎng)卡緩沖區(qū)中的數(shù)據(jù)(利用send或write等)較小時优幸,可能不會立即發(fā)出去吨拍,只要當多次send或者

write之后,網(wǎng)卡緩沖區(qū)中的數(shù)據(jù)足夠多時网杆,才會一次性被協(xié)議棧發(fā)送出去羹饰,操作系統(tǒng)利用這個算法減少網(wǎng)絡(luò)通信次數(shù),提高網(wǎng)絡(luò)利用率碳却。對于實時性要求比較高的應(yīng)用來說队秩,可以禁用nagle算法。這

樣send或write的小數(shù)據(jù)包會立刻發(fā)出去昼浦。系統(tǒng)默認是開啟的馍资,禁用方法如下:

? ? ? ? long noDelay = 1; ?

? ? ?? setsockopt(m_hSocket, IPPROTO_TCP, TCP_NODELAY,(LPSTR)&noDelay, sizeof(long)); ? ? ? //noDelay為1-禁用,0-啟用

(5)linux epoll模型:Linux 從內(nèi)核 2.6引入epoll模型,首先創(chuàng)建fd函數(shù):

? ? ?? #include<sys/epoll.h>

? ? ?? int epoll_create(int size);? //size?從 Linux 2.6.8 以后就不再使用关噪,但是必須設(shè)置一個大于 0 的值 ,返回-1表示創(chuàng)建失敗

? ? ?? int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event); // 綁定事件,返回-1表示失敗鸟蟹,參數(shù)?epfd?即上文提到的 epollfd,參數(shù)?op表示操作類型使兔,EPOLL_CTL_ADD(添加)建钥、

EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(刪除)虐沥,當操作類型為NULL時熊经,第四個參數(shù) 可以設(shè)置NULL,參數(shù)?fd欲险,即需要被操作的 fd奈搜,參數(shù)?event,一個?epoll_event?結(jié)構(gòu)體的地址盯荤,

epoll_event?結(jié)構(gòu)體定義如下:

? ? ? ?? struct epoll_event

? ? ? ? {

? ? ? ? ? ? ?? uint32_t?????events;??????/*?需要檢測的?fd?事件馋吗,取值與?poll?函數(shù)一樣?*/

? ? ? ? ? ? ?? epoll_data_t?data;????????/*?用戶自定義數(shù)據(jù), 本質(zhì)上是一個 Union 對象秋秤,8個字節(jié)*/

? ? ? ?? };?

? ?? int epoll_wait(int epfd,struct epoll_event*?events,int maxevents,int timeout); //檢測事件 宏粤,參數(shù)?events?是一個?epoll_event?結(jié)構(gòu)數(shù)組的首地址脚翘,這是一個輸出參數(shù),函數(shù)調(diào)用成功后绍哎,events?中存放?

的是與就緒事件相關(guān)?epoll_event?結(jié)構(gòu)體數(shù)組来农;參數(shù)?maxevents?是數(shù)組元素的個數(shù);timeout?是超時時間崇堰,單位是毫秒沃于,如果設(shè)置為 0,epoll_wait?會立即返回海诲。當?epoll_wait?調(diào)用成功會返回有事件

的 fd 數(shù)目繁莹;如果返回 0 表示超時;調(diào)用失敗返回 -1特幔。如下例子所示:

while?(true)

{

????epoll_event?epoll_events[1024];

????int?n?=?epoll_wait(epollfd,?epoll_events,?1024,?1000);

????if?(n?<?0)

????{

????????//被信號中斷

????????if?(errno?==?EINTR)

????????????continue;

????????//出錯咨演,退出

????????break;

????}

????else?if?(n?==?0)

????{

????????//超時,繼續(xù)

????????continue;

????}

????for?(size_t?i?=?0;?i?<?n;?++i)

????{

????????//?處理可讀事件

????????if?(epoll_events[i].events?&?POLLIN)

????????{

????????}

????????//?處理可寫事件

????????else?if?(epoll_events[i].events?&?POLLOUT)

????????{

????????}

????????//處理出錯事件

????????else?if?(epoll_events[i].events?&?POLLERR)

????????{

????????}

????}

}

? ? ? ? ? epoll_wait 與 poll 的區(qū)別:epoll_wait?函數(shù)調(diào)用完之后蚯斯,我們可以直接在?event?參數(shù)中拿到所有有事件就緒的 fd薄风,直接處理即可(event?參數(shù)僅僅是個出參);而?poll?函數(shù)的事件集合調(diào)用前后

數(shù)量都未改變拍嵌,只不過調(diào)用前我們通過?pollfd?結(jié)構(gòu)體的?events?字段設(shè)置待檢測事件遭赂,調(diào)用后我們需要通過?pollfd?結(jié)構(gòu)體的?revents?字段去檢測就緒的事件( 參數(shù)?fds?既是入?yún)⒁彩浅鰠ⅲ?/p>

? ? ? ? ?? 與 poll 的事件宏相比,epoll 新增了一個事件宏EPOLLET横辆,這就是所謂的邊緣觸發(fā)模式(EdgeTrigger嵌牺,ET),而默認的模式我們稱為水平觸發(fā)模式(LevelTrigger龄糊,LT)逆粹。這兩種模式的區(qū)別在于:

? ? ? ? ? 對于水平觸發(fā)模式,一個事件只要有炫惩,就會一直觸發(fā)僻弹;(讀取數(shù)據(jù)時可選擇讀取字節(jié)數(shù)目)

? ? ? ? ? 對于邊緣觸發(fā)模式,只有一個事件從無到有才會觸發(fā)他嚷。(因此讀取數(shù)據(jù)時要一次性全部讀完蹋绽,循環(huán)調(diào)用 recv 函數(shù)直到 recv 出錯,錯誤碼是EWOULDBLOCK(EAGAIN?一樣))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筋蓖,一起剝皮案震驚了整個濱河市卸耘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粘咖,老刑警劉巖蚣抗,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瓮下,居然都是意外死亡翰铡,警方通過查閱死者的電腦和手機钝域,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锭魔,“玉大人例证,你說我怎么就攤上這事∶耘酰” “怎么了织咧?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漠秋。 經(jīng)常有香客問我笙蒙,道長,這世上最難降的妖魔是什么膛堤? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任手趣,我火速辦了婚禮晌该,結(jié)果婚禮上肥荔,老公的妹妹穿的比我還像新娘。我一直安慰自己朝群,他們只是感情好燕耿,可當我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著姜胖,像睡著了一般誉帅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上右莱,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天蚜锨,我揣著相機與錄音,去河邊找鬼慢蜓。 笑死亚再,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晨抡。 我是一名探鬼主播氛悬,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼耘柱!你這毒婦竟也來了如捅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤调煎,失蹤者是張志新(化名)和其女友劉穎镜遣,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體士袄,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡烈涮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年朴肺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坚洽。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡戈稿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出讶舰,到底是詐尸還是另有隱情鞍盗,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布跳昼,位于F島的核電站般甲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鹅颊。R本人自食惡果不足惜敷存,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望堪伍。 院中可真熱鬧锚烦,春花似錦、人聲如沸帝雇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尸闸。三九已至彻亲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吮廉,已是汗流浹背苞尝。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宦芦,地道東北人宙址。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像踪旷,于是被迫代替她去往敵國和親曼氛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,937評論 2 361

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