1. 程式人生 > >bind函式和accept函式使用中的常見坑解析

bind函式和accept函式使用中的常見坑解析

首先先看這兩個函式:

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也會被重新賦值。

 

總結一下傳入傳出引數的使用:

  • 傳入的引數,需要在傳入之前,先初始化好一個實際值
  • 傳出的引數,要加“&”取地址。