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ù)(查手冊即可)