socket();創(chuàng)建一個套接字

當前正在學習的網(wǎng)絡(luò)編程是基于linux系統(tǒng)的C++網(wǎng)絡(luò)編程,上面是在linux下的socket定義
輸入:
domain:翻譯為域,這里就是制定為套接字選擇的地址協(xié)議,常見的有IPV4、IPV6等
AF_INET IPv4 Internet protocols
AF_INET6 IPv6 Internet protocols
AF_UNIX Local communication
(linux翻譯)domain參數(shù)指定通信域;這將選擇用于通信的協(xié)議族。
type:創(chuàng)建套接字選擇的數(shù)據(jù)傳輸協(xié)議,常見的有SOCK_STREAM數(shù)據(jù)流協(xié)議、SOCK_DGRAM數(shù)據(jù)報協(xié)議,一種是基于TCP協(xié)議,一種基于UDP協(xié)議
(linux)套接字具有指定的類型,該類型指定通信語義。當前定義的類型有:
SOCK_STREAM提供有序的、可靠的、雙向的、基于連接的字節(jié)流。帶外數(shù)據(jù)傳輸機制可以被支持。
SOCK_DGRAM支持數(shù)據(jù)報(無連接,固定最大長度的不可靠消息)。
protocol:協(xié)議類型,這個我也說不太清楚,一般默認為0即可
(linux)協(xié)議指定套接字要使用的特定協(xié)議。通常只存在一個單獨的協(xié)議來支持一個部分
指定協(xié)議族中的Ular套接字類型,在這種情況下,protocol可以指定為0。然而,有可能很多
協(xié)議可能存在,在這種情況下,必須以這種方式指定特定的協(xié)議。使用的協(xié)議號是特定的
“交流領(lǐng)域”,交流將在其中發(fā)生;看到協(xié)議(5)。如何映射協(xié)議名請參見getprotoent(3)
協(xié)議號的字符串。
返回值:等下來補充
示例:
#include <sys/types.h> /* See NOTES */
?#include <sys/socket.h>
socket(AF_INET,SOCK_STREAM,0);
bind();給套接字綁定一個名稱,根據(jù)里面要傳遞的參數(shù),其實就是給套接字綁定一個地址,這里后面等下會具體來說
struct sockaddr{
sa_family_t sa_family;
char sa_data[14];
};

sockfd:socket函數(shù)的返回值
const struct sockaddr *addr:要說起這個函數(shù),可能需要提到一個概念性的問題。

上面是sockaddr的結(jié)構(gòu),因此為了傳入有效的參數(shù),我們需要去給參數(shù)進行賦值。
struce sockaddr_in addr;//初始化sockaddr,其實就是將sockaddr_in的結(jié)構(gòu)用于sockaddr,具體原因我后面也會補充
addr.sin_family=AF_INET;
addr.sin_port=htons(8888);
addr.sin_addr.s_addr=htonl(INADDR_ANY);//默認寫法
addr:&addr
addrlen:地址結(jié)構(gòu)的大小,sizeof(addr)
這里時間不是很夠,后面我會根據(jù)我的理解給出上面一些參數(shù)的原因,總的來說,參數(shù)的選擇是跟套接字創(chuàng)建的時候的參數(shù)某種程度上面保持了一致性。
Linux:
下面是linux系統(tǒng)中,在創(chuàng)建套接字的過程中,使用了AF_UNIX,所以my_addr.sun_family = AF_UNIX;我的理解是這些部分是有一些聯(lián)系的,而且在使用AF_UNIX之后,并不需要使用sockaddr_in
暫時說說我的理解(還沒有去證實)sockaddr_in,用于IPV4通信
sockaddr_in6很顯然,用于IPV6的通信
(一些其他的觀點等待去驗證)
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un my_addr, peer_addr;
my_addr.sun_family = AF_UNIX;
if (bind(sfd, (struct sockaddr *) &my_addr,
? ? ? ? ? ? ? ? ? sizeof(my_addr)) == -1)
? ? ? ? ? ? ? handle_error("bind");
返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
成功返回0,不成功返回-1,如果有錯誤就返回錯誤
示例:
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htonl(8888)
addr.sin_addr.s_addr=htonl(INADDR_ANY)
int sfd;
sfd=socket(.......);
bind(sfd,(struct sockaddr*)&addr,sizeof(addr);
listen();listen - listen for connections on a socket,設(shè)置與套接字連接的服務(wù)器的上限數(shù)值(同時與服務(wù)器進行3次握手的客戶端數(shù)量)

sockfd:sockfd參數(shù)是一個文件描述符,引用SOCK_STREAM或SOCK_SEQPACKET類型的套接字。
這里的sockfd與bind()函數(shù)中的sockfd相同,都是socket();函數(shù)的返回值
backlog:backlog參數(shù)定義了sockfd的掛起連接隊列可以增長到的最大長度。上限數(shù)值,最大128
返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
成功返回0
示例:
int cfd;
struct sockaddr_in addr;
addr.sin_famliy=AF_INET;
addr.sin_port=htonl(8888);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
cdf=socket(AF_INET,SOCK_STREAM,0);
accept(); accept a connection on a socket 阻塞客戶端建立連接,成功的話,返回一個與客戶端成功建立連接的套接字
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept()系統(tǒng)調(diào)用用于基于連接的套接字類型(SOCK_STREAM, SOCK_SEQPACKET)。它提取掛起連接隊列上的第一個連接請求。監(jiān)聽套接字sockfd創(chuàng)建一個新的已連接套接字,并返回一個引用該套接字的新文件描述符。創(chuàng)建的套接字不在監(jiān)聽狀態(tài)。原始套接字sockfd不受此調(diào)用的影響。參數(shù)sockfd是一個用socket(2)創(chuàng)建的套接字,用bind(2)綁定到本地地址,在listen(2)之后監(jiān)聽連接。
sockfd:套接字的返回值,準確的來說是服務(wù)器端通過調(diào)用正確調(diào)用socket -> bind -> listen 函數(shù)之后的用于指向存放多個客戶端緩沖隊列緩沖區(qū)的套接字描述符
*addr:是用來保存客戶端套接字對應(yīng)的內(nèi)存空間變量(包括客戶端IP和端口信息等)
*addrlen:第二個參數(shù)的大小
addr是一個傳出參數(shù),
示例:
connect();在一個套接字上面創(chuàng)建連接
connect()系統(tǒng)調(diào)用將文件描述符sockfd引用的套接字連接到由addr指定的地址。參數(shù)addrlen指定了addr的大小。addr中的地址格式由套接字sockfd的地址空間決定;詳見socket(2)。如果套接字sockfd類型為SOCK_DGRAM,則addr是缺省情況下發(fā)送數(shù)據(jù)報的地址,也是接收數(shù)據(jù)報的唯一地址。如果socket類型為SOCK_STREAM或SOCK_SEQPACKET,則該調(diào)用嘗試建立到綁定到addr指定地址的套接字的連接。一些協(xié)議套接字(例如UNIX域流套接字)可能只能成功地連接()一次。一些協(xié)議套接字(例如UNIX和Internet域中的數(shù)據(jù)報套接字)可能多次使用connect()來更改它們的關(guān)聯(lián)。一些協(xié)議套接字(例如,TCP套接字以及UNIX和Internet域中的數(shù)據(jù)報套接字)可以通過連接到帶有的地址來解除關(guān)聯(lián)sockaddr的sa_family成員設(shè)置為AF_UNSPEC;此后,套接字可以連接到另一個地址。(AF_UNSPEC自內(nèi)核2.2起在Linux上得到支持。)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd:產(chǎn)生的套接字參數(shù)
*addr:傳入?yún)?shù),指定服務(wù)器端地址信息,含IP地址和端口號
addrlen:第二個參數(shù)的長度
到這里,基本的通信所用到的函數(shù)就介紹完畢了,這兩天也找了很多資料,但是始終很難有一個茅塞頓開的醒悟,所以就先暫時到這吧,后面繼續(xù)學習,有了感悟,我會再后面重新再寫一遍函數(shù)的介紹,總的來說,對于accept、socket等函數(shù)印象很深刻,但是對于connect以及bind還是有點模糊的概念,因為我確實也沒搞定,某些參數(shù)的由來,雖然linux系統(tǒng)下面提供了源碼,我也看了一些,但是確實還是很難理解,但是我記得這里是一個疑點,往后面學習,我還會回來的!
上次少更新的兩個函數(shù),在后面學習的過程中我才發(fā)現(xiàn),現(xiàn)在先來簡單說一下啦
inet_pton();
說到最后這兩個函數(shù),就要提到一些概念性的定義,例如我們常見的IP:192.168.8.88,這是一個十進制的網(wǎng)絡(luò)字節(jié)序,但是在我們計算機中的網(wǎng)絡(luò)字節(jié)序,可不是這種,而是一種二進制的網(wǎng)絡(luò)字節(jié)序。
網(wǎng)絡(luò)字節(jié)序:
類型:大端字節(jié)序、小端字節(jié)序
大端:最高有效位存于最低內(nèi)存地址處,最低有效位存于最高內(nèi)存處;(低到高)
小端:最高有效位存于最高內(nèi)存地址,最低有效位存于最低內(nèi)存處。(高到低)
? ??

這里由于一些原因,導致我們電腦本機使用的是小端字節(jié)序,而在網(wǎng)絡(luò)中的數(shù)據(jù)傳輸使用的是大端字節(jié)序,因此在對數(shù)據(jù)進行傳世時,需要進行轉(zhuǎn)化。而現(xiàn)在也有著一些很合適的轉(zhuǎn)化函數(shù)
1.htons、htonl,解釋為Host to Network,從主機轉(zhuǎn)換到網(wǎng)路,也就是表明,講字節(jié)序由小端轉(zhuǎn)化為大端,兩個函數(shù)的區(qū)別主要是返回值的長短不同,s表示返回unsigned short int,l表示返回unsigned int
2、ntohs、ntohl,聽懂了上面的解釋,這兩個函數(shù)的意思就顯而易見了。Netword to Host,網(wǎng)絡(luò)中的大端字節(jié)序轉(zhuǎn)化為Host中的小端字節(jié)序。
后面的s、l是同一個意思,只是返回的值部同
明白了網(wǎng)絡(luò)字節(jié)序,就明白了數(shù)據(jù)在網(wǎng)絡(luò)中的傳輸基本都是二進制形式的,但是我們還是會經(jīng)??吹絠p 192.128.66.255 193.253.255.21等等這些ip,但是這些ip有一個共同的特點,就是這些ip都使用了十進制來表示,但是在機器語言中,傳遞的數(shù)據(jù)可能是這樣0000. 0125.2352.1563
所以這里牽扯到如何講ip轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序的,這個地方就是我們今天要說的函數(shù),inet_pton,inet_ntop,
兩個函數(shù)就是將網(wǎng)絡(luò)字節(jié)序和正常人類能看懂的進行一個轉(zhuǎn)換,
1100.1200.1300.1400
所以在某些函數(shù)里面是需要使用十進制二維碼,當然也可以手動轉(zhuǎn)換
為此,這兩個函數(shù)起到十進制和網(wǎng)絡(luò)字節(jié)序之間的轉(zhuǎn)換。