2014-05-13 48 views
2

我在努力理解accept(2)的原型。爲什麼`accept(2)`需要'sockaddr`長度作爲單獨的指針?

我有一個簡單的服務器接受連接並向客戶端返回「Hello world!\ n」。系統調用accept(2)需要一個指向struct sockaddr的指針和一個指向socklen_t的指針來存儲結構的長度。但sockaddr已經有一個名爲sa_len的字段,這似乎是爲此而完成的。另外,我有這個簡單的服務器(在OSX下編譯,希望Linux也可以)打印出我自己的socklen_t傳遞給接受,然後sa_len的值:它們是相同的,在這種情況下,在OSX上是28。

編輯:經過多一點測試,看起來sa_len不一定與存儲在指針中的長度相同。

爲什麼accept(2)需要長度作爲單獨的指針?


僅供參考,我在下面發佈示例服務器。你可以編譯:

gcc -Wall -Wextra main.c 

然後運行:

./a.out 

在另一端,連接到它:

telnet 127.0.0.1 3000 

#include <errno.h> 
#include <sys/socket.h> 
#include <unistd.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <netinet/in.h> 
#include <strings.h> 

// default port if none if passed in the program arguments 
#define FTP_PORT_DEFAULT ("3000") 

// number of connections allow to wait for a call to accept 
#define FTP_BACKLOG (5) 

int main(int ac, char **av) 
{ 
    struct addrinfo  hints; // hints used to get address information 
    struct addrinfo  *sai; // server address information 
    int     ss; // server socket 
    char   *port; 

    port = (ac >= 2) ? av[1] : FTP_PORT_DEFAULT; 
    bzero(&hints, sizeof(hints)); 

    // using AF_INIT6 instead of PF_INET6 
    // http://stackoverflow.com/questions/6729366/ 
    hints.ai_family = AF_INET6; 
    hints.ai_socktype = SOCK_STREAM; 

    // intended for use with `bind` 
    hints.ai_flags = AI_PASSIVE; 

    // passing `NULL` as the hostname tells `getaddrinfo` to use 
    // any available local IP address 
    if (getaddrinfo(NULL, port, &hints, &sai) != 0) 
     return (-1); 

    if ((ss = 
     socket(sai->ai_family, sai->ai_socktype, sai->ai_protocol))== -1) 
     return (-1); 

    if (bind(ss, sai->ai_addr, sai->ai_addrlen) == -1 || 
     listen(ss, FTP_BACKLOG) == -1) 
    { 
     close(ss); 
     return (-1); 
    } 

    while (1) 
    { 
     int cs; 
     struct sockaddr csockaddr; 
     unsigned csockaddr_len; 

     bzero(&csockaddr, sizeof(csockaddr)); 
     cs = accept(ss, &csockaddr, &csockaddr_len); 
     // handle "fatal" errors that I don't think I can recover from 
     // other than by relaunching the server 
     if (cs == EBADF || cs == ECONNABORTED || cs == ENOTSOCK || 
       cs == EOPNOTSUPP) 
     { 
      break ; 
     } 
     printf("my len %u/internal len %u\n", 
        csockaddr_len, csockaddr.sa_len); 

     if (fork() == 0) 
     { 
      write(cs, "Hello world!\n", 13); 
      close(cs); 
     } 
     break; 
    } 
    close(ss); 

    return 0; 
} 
+2

'accept'實際上需要'socklen_t *',而不是'unsigned int *'。在4.3BSD中,它在早期的POSIX版本中使用了'int *',然後是'size_t *',然後POSIX改變了主意並將其留給實現來將'socklen_t'定義爲這兩種類型之一。 –

+0

你說得對。我在OSX上似乎使用'unsigned int'。在問題中糾正了它。 – conradkdotcom

+0

您需要在調用accept之前初始化csockaddr_len。 accept(2)手冊頁包含詳細信息。 – sigjuice

回答

相關問題