uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
?
int inet_pton(int family, const char *strptr, void *addrptr);
分析:
- 第一個參數可以是AF_INET或AF_INET6:
- 第二個參數是一個指向點分十進制串的指針:
- 第三個參數是一個指向轉換后的網絡字節序的二進制值的指針。
?
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
分析:
- 第一個參數可以是AF_INET或AF_INET6:
- 第二個參數是一個指向網絡字節序的二進制值的指針;
- 第三個參數是一個指向轉換后的點分十進制串的指針;
- 第四個參數是目標的大小,以免函數溢出其調用者的緩沖區
?
strcut sockaddr 很多網絡編程函數誕生早于IPv4協議,那時候都使用的是sockaddr結構體,為了向前兼容,現在sockaddr退化成了(void *)的作用,傳遞一個地址給函數,至于這個函數是sockaddr_in還是sockaddr_in6,由地址族確定,然后函數內部再強制類型轉化為所需的地址類型。
?1. socketaddr_in結構體:
struct sockaddr_in
{sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */
};struct in_addr
{uint32_t s_addr; /* address in network byte order */
};
套接字api
?1. socket函數原型:
int socket(int domain, int type, int protocol);
分析:
-
成功:返回指向新創建的socket的文件描述符,失敗:返回-1,設置errno
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
分析:
- sockfd:socket文件描述符
- addr:構造出IP地址加端口號
- addrlen:sizeof(addr)長度
- 返回值:功返回0,失敗返回-1, 設置errno
?【注意】:服務器程序所監聽的網絡地址和端口號通常是固定不變的,客戶端程序得知服務器程序的地址和端口號后就可以向服務器發起連接,因此服務器需要調用bind綁定一個固定的網絡地址和端口號。bind()的作用是將參數sockfd和addr綁定在一起,使sockfd這個用于網絡通訊的文件描述符監聽addr所描述的地址和端口號。前面講過,struct sockaddr *是一個通用指針類型,addr參數實際上可以接受多種協議的sockaddr結構體,而它們的長度各不相同,所以需要第三個參數addrlen指定結構體的長度。如:
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
?首先將整個結構體清零,然后設置地址類型為AF_INET,網絡地址為INADDR_ANY,這個宏表示本地的任意IP地址,因為服務器可能有多個網卡,每個網卡也可能綁定多個IP地址,這樣設置可以在所有的IP地址上監聽,直到與某個客戶端建立了連接時才確定下來到底用哪個IP地址,端口號為6666
int listen(int sockfd, int backlog);
- sockfd:socket文件描述符
- backlog:排隊建立3次握手隊列和剛剛建立3次握手隊列的鏈接數和
【注意】:典型的服務器程序可以同時服務于多個客戶端,當有客戶端發起連接時,服務器調用的accept()返回并接受這個連接,如果有大量的客戶端發起連接而服務器來不及處理,尚未accept的客戶端就處于連接等待狀態,listen()聲明sockfd處于監聽狀態,并且最多允許有backlog個客戶端處于連接待狀態,如果接收到更多的連接請求就忽略。listen()成功返回0,失敗返回-1。
?
?
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函數原型:?
- sockdf:socket文件描述符
- addr:傳出參數,返回鏈接客戶端地址信息,含IP地址和端口號
- addrlen:傳入傳出參數(值-結果),傳入sizeof(addr)大小,函數返回時返回真正接收到地址結構體的大小
- 返回值:成功返回一個新的socket文件描述符,用于和客戶端通信,失敗返回-1,設置errno
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
?分析:
- sockdf:socket文件描述符
- addr:傳入參數,指定服務器端地址信息,含IP地址和端口號
- addrlen:傳入參數,傳入sizeof(addr)大小
- 返回值:成功返回0,失敗返回-1,設置errno
【注意】:客戶端需要調用connect()連接服務器,connect和bind的參數形式一致,區別在于bind的參數是自己的地址,而connect的參數是對方的地址。connect()成功返回0,出錯返回-1。