bind函式和accept函式使用中的常見坑解析
阿新 • • 發佈:2019-01-13
首先先看這兩個函式:
bind():
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 第一個引數sockfd使用的應該是伺服器端的socket檔案描述符。
- 第二個引數const struct sockaddr *addr是構造出的IP地址和埠號。
- 第三個引數是addr的長度。
- bind函式的返回值為“0”則建立成功。失敗返回-1,設定errno。
accept():
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 第一個引數sockfd同bind也是伺服器端的socket檔案描述符。
- 第二個引數addr是傳出引數,返回連結客戶端的地址資訊,其中包含IP地址和埠號。
- 第三個引數addrlen是一個傳入傳出引數,傳入的,是sizeof(addr)的大小函式在返回時,則返回的是真正接收到地址結構體的大小
- accept函式的返回值則是建立結果,如果建立成功,返回的是新的客戶端的socket檔案描述符,用於和客戶端通訊,建立失敗則返回-1,設定errno。
這裡需要注意的是:
一、sockaddr的問題
在兩個函式中,都是使用了struct sockaddr型別的引數。這個結構體的定義為:
struct sockaddr {
sa_family_t sa_family; //16位的地址型別
char sa_data[14]; //14位元組的地址資料
};
但是在現代程式設計中sockaddr型別已經被廢棄,取而代之的是struct sockaddr_in,定義為:
struct sockaddr_in {
__kernel_sa_family_t sin_family; /* Address family */ 地址結構型別
__be16 sin_port; /* Port number */ 埠號
struct in_addr sin_addr; /* Internet address */ IP地址
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
所以,我們需要在程式設計的過程中,使用scokaddr_in來傳值,然後,在後續傳參的時候,把sockaddr_in強制轉換成sockaddr來使用。
比如:
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr= htonl(INADDR_ANY);
bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
cfd=accept(lfd,(struct sockaddr *)&clie_addr,&clie_addr_len);
二、傳入傳出引數的問題:
通過觀察bind和accept函式的引數,可以發現:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
兩個函式的定義中第三個引數,一個是socklen_t addrlen,一個是socklen_t *addrlen。
bind函式中soclen_t addr表示:這是一個傳入引數,在使用的時候,可以像上文的程式中一樣,直接sizeof(serv_addr)傳值進去。
accpet函式中socklen_t *addr表示:這是一個傳入傳出引數,在使用的時候,必須先在socklen中宣告之後,才可以使用。在accpet函式返回的時候,*addr也會被重新賦值。
總結一下傳入傳出引數的使用:
- 傳入的引數,需要在傳入之前,先初始化好一個實際值
- 傳出的引數,要加“&”取地址。