ngx_request_t結構體中有一個connection定義,該定義指向一個ngx_connection_t的結構體:
結構體定義如下:
1 struct ngx_connection_s { 2 void *data; 3 ngx_event_t *read; 4 ngx_event_t *write; 5 6 ngx_socket_t fd; 7 8 ngx_recv_pt recv; 9 ngx_send_pt send; 10 ngx_recv_chain_pt recv_chain; 11 ngx_send_chain_pt send_chain; 12 13 ngx_listening_t *listening; 14 15 off_t sent; 16 17 ngx_log_t *log; 18 19 ngx_pool_t *pool; 20 21 struct sockaddr *sockaddr; 22 socklen_t socklen; 23 ngx_str_t addr_text; 24 25 ngx_str_t proxy_protocol_addr; 26 27 #if (NGX_SSL) 28 ngx_ssl_connection_t *ssl; 29 #endif 30 31 struct sockaddr *local_sockaddr; 32 socklen_t local_socklen; 33 34 ngx_buf_t *buffer; 35 36 ngx_queue_t queue; 37 38 ngx_atomic_uint_t number; 39 40 ngx_uint_t requests; 41 42 unsigned buffered:8; 43 44 unsigned log_error:3; /* ngx_connection_log_error_e */ 45 46 unsigned unexpected_eof:1; 47 unsigned timedout:1; 48 unsigned error:1; 49 unsigned destroyed:1; 50 51 unsigned idle:1; 52 unsigned reusable:1; 53 unsigned close:1; 54 55 unsigned sendfile:1; 56 unsigned sndlowat:1; 57 unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ 58 unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ 59 60 unsigned need_last_buf:1; 61 62 #if (NGX_HAVE_IOCP) 63 unsigned accept_context_updated:1; 64 #endif 65 66 #if (NGX_HAVE_AIO_SENDFILE) 67 unsigned busy_count:2; 68 #endif 69 70 #if (NGX_THREADS) 71 ngx_thread_task_t *sendfile_task; 72 #endif 73 };
結構體中,有兩個sockaddr地址結構定義,分別是sockaddr以及local_sockaddr;前者為客戶端地址,后者為服務器端地址;下面來看sockaddr的定義:
struct sockaddr { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };
說明:
sa_family是地址家族,是“AF_xxx”的形式。常設為“AF_INET”,代表Internet(TCP/IP)地址族。
sa_data是協議地址,由sa_family決定。如果sa_family=AF_INET,則sa_data就是sockaddr_in的 sin_addr和sin_port,用於為套接口儲存目標地址和端口信息。為了解決struct sockaddr賦值以及訪問,提供了了一個並列的結構struct sockadd_in(“in”代表
“Internet”),換句話說,sockaddr的數據存儲大小和結構完全和sockaddr_in一致,可以直接強制轉換。
sa_data是協議地址,由sa_family決定。如果sa_family=AF_INET,則sa_data就是sockaddr_in的 sin_addr和sin_port,用於為套接口儲存目標地址和端口信息。為了解決struct sockaddr賦值以及訪問,提供了了一個並列的結構struct sockadd_in(“in”代表
“Internet”),換句話說,sockaddr的數據存儲大小和結構完全和sockaddr_in一致,可以直接強制轉換。
struct sockaddr_in{ short int sin_family; /*地址族信息,通常是AF-xxxx的形式*/ unsigned short int sin_port; /*端口信息*/ struct in_addr sin_addr; /*網絡地址*/ unsigned char sin_zero[8]; /*補位用的0,to make same size as struct sockaddr*/ }
關於這兩個結構體,他們占用的內存大小是一樣的,當sockaddr_in.sin_family = AF_INET時,他們的內存布局也一樣的!看看sockaddr結構體自身就知道了,它僅僅是個char數組,大小與sockaddr_in等同。
這兩個結構體使用轉化的例子如下:
- sockaddr_in結構強制轉換成sockaddr結構再傳入系統調用函數
/*sockaddr_in強制轉化為sockaddr,用於傳入系統調用函數*/ int sockfd; struct sockaddr_in my_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; /* 主機字節序 */ my_addr.sin_port = htons(MYPORT); /* short, 網絡字節序 */ my_addr.sin_addr.s_addr = inet_addr("192.168.0.1"); bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */ //memset(&my_addr.sin_zero, 0, 8); bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));//將sockaddr_in強制轉化為sockaddr,用於傳入系統調用函數
- sockaddr結構強制轉換成sockaddr_in結構,從而得到ip地址和端口號
struct sockaddr_in *ip = (struct sockaddr_in *) (r->connection->sockaddr); char* addr = inet_ntoa(ip->sin_addr);//地址轉化函數,返回字符串指針 unsigned short port = ntohs(ip->sin_port);//大小端轉換
