Socket編程(3)-Socket API

1 Socket API函數(shù)

WinSock的實(shí)現(xiàn)方式是利用Windows的動態(tài)鏈接庫實(shí)現(xiàn)的,所以如果在Windows環(huán)境下進(jìn)行socket編程,需要事先初始化Windows Sockets API,可以通過調(diào)用WSAStartup()完成。在使用結(jié)束后釋放所使用的Windows Sockets DLL,可以通過調(diào)用WSACleanup()來完成。這里的WSA指的是Windows Socket Asynchronous智听,即Windows異步套接字。
在Linux下可使用man命令查閱相關(guān)API函數(shù)的詳細(xì)信息渡紫。

1.1 WSAStartup

// #include <WinSock2.h>
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
  • Windows特有到推,使用Socket的應(yīng)用程序在使用Socket之前必須先調(diào)用WSAStartup函數(shù)。
  • 兩個(gè)參數(shù):
    • WORD wVersionRequested:指明程序請求使用的WinSock版本惕澎,其中高位字節(jié)指明副版本莉测、低位字節(jié)指明主版本。十六進(jìn)制整數(shù)集灌,例如0x102表示2.1版本悔雹。
    • LPWSADATA lpWSAData:返回實(shí)際的WinSock的版本信息,為指向WSADATA結(jié)構(gòu)的指針欣喧。

例:使用2.2版本的WinSock的程序代碼段

wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);

1.2 WSACleanup

// #include <WinSock2.h>
int WSACleanup(void);
  • Windows特有腌零,應(yīng)用程序在完成對請求的Socket庫的使用,最后要調(diào)用WSACleanup函數(shù)唆阿,可以解除與Socket庫的綁定和釋放Socket庫所占用的系統(tǒng)資源益涧。

1.3 socket

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
int socket(int domain, int type, int protocol);
  • 創(chuàng)建套接字時(shí)使用,操作系統(tǒng)會返回套接字描述符驯鳖。最初是面向TCP/IP協(xié)議棧的闲询,但最終設(shè)計(jì)成可以面向其他協(xié)議簇。
  • 三個(gè)參數(shù):
    • int domain:指定協(xié)議簇浅辙,主要用TCP/IP協(xié)議扭弧,因此可指定為PF_INET符號常量,這里AF_INET和PF_INET是一樣的记舆,這是歷史遺留問題造成的鸽捻。協(xié)議簇主要有AF_INET(IPv4)、AF_INET6(IPv6)泽腮、AF_LOCAL(UNIX協(xié)議) AF_ROUTE(路由套接字)御蒲、AF_KEY(秘鑰套接字)。
    • int type:指定套接字類型诊赊,主要有面向TCP的套接字SOCK_STREAM厚满,又稱流式套接字;面向UDP的套接字SOCK_DGRAM碧磅,又稱數(shù)據(jù)報(bào)套接字碘箍。TCP:可靠遵馆、面向連接、字節(jié)流傳輸丰榴、點(diǎn)對點(diǎn)团搞;UDP:不可靠、無連接多艇、數(shù)據(jù)報(bào)傳輸。
    • int protocol:指定協(xié)議號像吻,0為默認(rèn)峻黍。需要使用別的協(xié)議才指定,如果套接字類型不是原始套接字拨匆,那么這個(gè)參數(shù)就為0姆涩。
  • 特殊情況:創(chuàng)建原始套接字SOCK_RAW(操作系統(tǒng)對這類套接字的創(chuàng)建需要有特殊的權(quán)限,Windows需要管理員權(quán)限惭每,Linux需要root權(quán)限)骨饿,可跨越傳輸層面向網(wǎng)絡(luò)層。

例:創(chuàng)建一個(gè)面向TCP/IP的流式套接字代碼段

struct protoent *p;
p = getprotobyname("tcp");
SOCKET sd = socket(PF_INET, SOCK_STREAM, p->p_proto);
五層模型 主要協(xié)議
應(yīng)用層
傳輸層 TCP/UDP
網(wǎng)絡(luò)層 IP/ICMP/IGMP
數(shù)據(jù)鏈路層
物理層

1.4 closesocket/close

int closesocket(SOCKET sd);    // Windows:#include <WinSock2.h>
int close(int fd);             // Linux:#include <unistd.h>
  • 關(guān)閉一個(gè)描述符為sd/fd的套接字台腥。
  • 如果多個(gè)進(jìn)程共享一個(gè)套接字宏赘,調(diào)用函數(shù)將套接字引用計(jì)數(shù)減1,減至0才關(guān)閉黎侈。
  • 一個(gè)進(jìn)程中的多線程對一個(gè)套接字的使用無計(jì)數(shù)察署。如果進(jìn)程中的一個(gè)線程調(diào)用函數(shù)將一個(gè)套接字關(guān)閉,該進(jìn)程中的其他線程也將不能訪問該套接字峻汉。
  • 返回值:0-成功贴汪,SOCKET_ERROR(-1)-失敗。

1.5 bind

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 
  • 綁定套接字的本地端點(diǎn)地址:IP地址+Port端口號休吠。
  • 三個(gè)參數(shù):
    • int sockfd:socket函數(shù)返回的套接字描述符扳埂。
    • const struct sockaddr *addr:結(jié)構(gòu)為sockaddr_in的端點(diǎn)地址,指向本地IP地址的結(jié)構(gòu)體指針瘤礁。
    • socklen_t addrlen:結(jié)構(gòu)長度阳懂。
  • 客戶程序一般不必顯式調(diào)用bind函數(shù),操作系統(tǒng)會幫忙設(shè)置蔚携。
  • 服務(wù)器需要調(diào)用綁定熟知的端口號希太,例如80端口。
  • IP地址在服務(wù)器使用時(shí)不應(yīng)該指定具體的IP地址酝蜒,因?yàn)榭赡苡卸鄠€(gè)網(wǎng)卡接收數(shù)據(jù)誊辉,較難確認(rèn),只需將IP地址賦值為INADDR_ANY地址通配符亡脑,即可監(jiān)聽所有地址接收的數(shù)據(jù)堕澄。
struct sockaddr{
     unsigned short sa_family; //通信協(xié)議類型族AF_xx
     char sa_data[14];  //14字節(jié)協(xié)議地址邀跃,包含該socket的IP地址和端口號
};

1.6 listen

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
int listen(int sockfd, int backlog);
  • 監(jiān)聽狀態(tài)函數(shù),置服務(wù)器端的流套接字處于監(jiān)聽狀態(tài)蛙紫,僅服務(wù)器端調(diào)用拍屑,并且僅用于面向連接的流式套接字。
  • 兩個(gè)參數(shù):
    • int sockfd:服務(wù)器端的流套接字坑傅,僅用于面向連接的流式套接字僵驰。
    • int backlog:設(shè)置連接請求隊(duì)列大小,即緩存隊(duì)列唁毒,可以設(shè)置連接客戶端的最大連接個(gè)數(shù)蒜茴,當(dāng)有多個(gè)客戶端向服務(wù)器請求時(shí),會受到此值的影響浆西,默認(rèn)值為20粉私。
  • 返回值:0-成功,SOCKET_ERROR(-1)-失敗近零。

1.7 connect

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
int connect(int sockfd,const struct sockaddr *addr, socklen_t addrlen)
  • 客戶端程序調(diào)用connect函數(shù)來使客戶套接字與特定計(jì)算機(jī)的特定端口的套接字連接诺核。
  • 僅用于客戶端, 可用于TCP客戶端久信,也可用于UDP客戶端窖杀。
    • TCP客戶端:建立TCP連接。
    • UDP客戶端:UDP是無連接的裙士,功能只是指定服務(wù)器端點(diǎn)地址陈瘦,實(shí)際是沒有連接的,但看著像連接一樣潮售。
  • 三個(gè)參數(shù):
    • int sockfd:客戶端套接字痊项。
    • const struct sockaddr *addr:服務(wù)端套接字地址。
    • socklen_t addrlen:服務(wù)端套接字長度酥诽。

1.8 accept

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
  • 服務(wù)器端程序調(diào)用accept函數(shù)鞍泉,從處于監(jiān)聽狀態(tài)的流套接字的客戶連接請求隊(duì)列中取出排在最前的一個(gè)客戶請求,并且創(chuàng)建一個(gè)新得套接字來與客戶端套接字創(chuàng)建連接通道肮帐。
  • 僅用于TCP套接字咖驮,僅用于服務(wù)器。
  • 三個(gè)參數(shù):
    • int sockfd:服務(wù)端套接字训枢。
    • const struct sockaddr *addr:客戶端套接字地址托修。
    • socklen_t *addrlen:客戶端套接字長度地址。
  • 如果使用主套接字與客戶端通信恒界,因?yàn)門CP是點(diǎn)對點(diǎn)連接睦刃,那么在某一時(shí)刻服務(wù)器就只能為一個(gè)客戶端提供服務(wù),而不能夠?qū)崿F(xiàn)并發(fā)的TCP服務(wù)器十酣。因此創(chuàng)建新套接字與客戶端通信涩拙,服務(wù)器通過多線程际长、多進(jìn)程創(chuàng)建新套接字,即可實(shí)現(xiàn)并發(fā)的TCP服務(wù)器兴泥。

1.9 send, sendto

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
  • send函數(shù)用于TCP套接字(客戶端與服務(wù)器端)或調(diào)用了connect函數(shù)的UDP客戶端套接字工育。
  • sendto函數(shù)用于UDP服務(wù)器端套接字與未調(diào)用connect函數(shù)的UDP客戶端套接字颅和。

1.10 recv, recvfrom

// Windows:#include <WinSock2.h>
// Linux:#include <sys/types.h> <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
  • recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)抄瑟,或者從調(diào)用了connect函數(shù)的UDP客戶端套接字接收服務(wù)器發(fā)來的數(shù)據(jù)。
  • recvfrom用于從UDP服務(wù)器端套接字與未調(diào)用用connect函數(shù)的UDP客戶端套接字接收對端數(shù)據(jù)软吐。

1.11 setsockopt, getsockopt

int setsockopt(int sd, int level, int optname, *optval, socklen_t optlen);
int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen);
  • setsockopt()函數(shù)用來設(shè)置套接字sd的選項(xiàng)參數(shù)旭贬。
  • getsockopt()函數(shù)用于獲取任意類型竭沫、任意狀態(tài)套接口的選項(xiàng)當(dāng)前值,并把結(jié)果存入optval骑篙。

2 Socket API函數(shù)小結(jié)

  • WSAStartup:初始化socket庫(僅對于WinSock)
  • WSACleanup:清除/終止socket庫的使用(僅對于WinSock)
    其他函數(shù)一般來說可以在Linux下使用,名稱基本一致
  • socket:創(chuàng)建套接字
  • connect:“連接”遠(yuǎn)端服務(wù)器(僅用于客戶端森书,注意TCP與UDP的區(qū)別)
  • closesocket/close:釋放/關(guān)閉套接字
  • bind:綁定套接字的本地IP地址和端口號(通嘲卸耍客戶端不需要,客戶端的端點(diǎn)地址- 操作系統(tǒng)會幫忙設(shè)置凛膏,不需要自己設(shè)置)
  • listen:置服務(wù)器端TCP套接字為監(jiān)聽模式杨名,并設(shè)置隊(duì)列大小(僅用于服務(wù)器端TCP套接字)
  • accept:接收/提取一個(gè)連接請求猖毫,創(chuàng)建新套接字台谍,通過新套接字與客戶端進(jìn)行連接(僅用于服務(wù)器端的TCP套接字,也稱為阻塞函數(shù))
  • recv:接收數(shù)據(jù)(用于TCP套接字或連接模式的客戶端UDP套接字)
  • recvfrom:接收數(shù)據(jù)報(bào)(用于非連接模式的UDP套接字)
  • send:發(fā)送數(shù)據(jù)(用于TCP套接字或連接模式的客戶端UDP套接字)
  • sendto:發(fā)送數(shù)據(jù)報(bào)(用于非連接模式的UDP套接字)
  • setsockopt:設(shè)置套接字選項(xiàng)參數(shù)(查手冊即可)
  • getsockopt:獲取套接字選項(xiàng)參數(shù)(查手冊即可)
Socket API調(diào)用基本流程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吁断,一起剝皮案震驚了整個(gè)濱河市趁蕊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仔役,老刑警劉巖掷伙,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異又兵,居然都是意外死亡任柜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門沛厨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宙地,“玉大人,你說我怎么就攤上這事逆皮≌啵” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵电谣,是天一觀的道長粹胯。 經(jīng)常有香客問我蓖柔,道長,這世上最難降的妖魔是什么风纠? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任况鸣,我火速辦了婚禮,結(jié)果婚禮上竹观,老公的妹妹穿的比我還像新娘镐捧。我一直安慰自己,他們只是感情好臭增,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布懂酱。 她就那樣靜靜地躺著,像睡著了一般誊抛。 火紅的嫁衣襯著肌膚如雪列牺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天拗窃,我揣著相機(jī)與錄音瞎领,去河邊找鬼。 笑死随夸,一個(gè)胖子當(dāng)著我的面吹牛九默,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宾毒,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼驼修,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诈铛?” 一聲冷哼從身側(cè)響起乙各,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幢竹,沒想到半個(gè)月后觅丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妨退,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年妇萄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咬荷。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冠句,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出幸乒,到底是詐尸還是另有隱情懦底,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布罕扎,位于F島的核電站聚唐,受9級特大地震影響丐重,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杆查,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一扮惦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亲桦,春花似錦崖蜜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舔琅,卻和暖如春等恐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背备蚓。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工课蔬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人星著。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像粗悯,于是被迫代替她去往敵國和親虚循。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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