2013-06-13 1 views
5

Unix 도메인 소켓으로 몇 가지 테스트를하고 있는데 문제없이 통신 할 수 있습니다. 그러나 내 테스트 프로그램의 서버 측에 accept()을 호출하면 struct sockaddr_unsun_path을 포함하지 않습니다.Unix Domain Sockets : accept() not sun_path를 설정하십시오.

Inet 소켓이 accept() 호출 후에 제대로 주소와 포트를 입력했는지 확신 할 수 있습니다. 테스트 프로그램에서 잘못되었거나 잘못된 결과가 예상됩니까?

CentOS 6.2 및 gcc 4.4.6을 실행 중입니다.

샘플 코드 :

server.c

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#define NAME "socket" 

int main(int argc, char **argv) 
{ 
    int sock, msgsock, rval; 
    struct sockaddr_un server, client; 
    char buf[1024]; 

    sock = socket(AF_UNIX, SOCK_STREAM, 0); 
    if (sock < 0) { 
     perror("opening stream socket"); 
     exit(1); 
    } 

    server.sun_family = AF_UNIX; 
    strcpy(server.sun_path, NAME); 

    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) { 
     perror("binding stream socket"); 
     exit(1); 
    } 

    printf("Socket has name %s\n", server.sun_path); 
    listen(sock, 5); 

    for (;;) { 
     socklen_t len = sizeof(client); 
     msgsock = accept(sock, (struct sockaddr *)&client, &len); 

     if (msgsock == -1) 
      perror("accept"); 
     else do { 
      printf("strlen(sun_path) = %zu\n", strlen(client.sun_path)); 

      bzero(buf, sizeof(buf)); 
      if ((rval = read(msgsock, buf, 1024)) < 0) 
       perror("reading stream message"); 
      else if (rval == 0) 
       printf("Ending connection\n"); 
      else 
       printf("-->%s\n", buf); 
     } while (rval > 0); 

     close(msgsock); 
    } 
    close(sock); 
    unlink(NAME); 

    return 0; 
} 

client.c

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#define DATA "Half a league, half a league . . ." 

int main(int argc, char **argv) 
{ 
    int sock; 
    struct sockaddr_un server; 

    if (argc < 2) { 
     printf("usage:%s <pathname>", argv[0]); 
     exit(1); 
    } 

    sock = socket(AF_UNIX, SOCK_STREAM, 0); 
    if (sock < 0) { 
     perror("opening stream socket"); 
     exit(1); 
    } 

    server.sun_family = AF_UNIX; 
    strcpy(server.sun_path, argv[1]); 

    if (connect(sock, (struct sockaddr *) &server, 
       sizeof(struct sockaddr_un)) < 0) { 
     close(sock); 
     perror("connecting stream socket"); 
     exit(1); 
    } 

    if (write(sock, DATA, sizeof(DATA)) < 0) 
     perror("writing on stream socket"); 

    close(sock); 

    return 0; 
} 

그냥 질문을 반복하기 :

후에 작성되지 sun_path

accept() 서버를 호출 하시겠습니까?

+0

정말 기적입니다.'len'은'sizeof (sa_family_t)'가되어 소켓에 묶여 있지 않을 때만 일어날 수 있습니다. 그러나 여러분의 경우에는 분명히 바인딩되어 있습니다 ... – kirelagin

+0

나도 노력했습니다. 추상 소켓으로, 다시,이 길이는 항상'2'이며, 그것은 명백히 잘못되었습니다. 이것은 man 페이지에 있습니다. – kirelagin

+0

이것이 정상적인 것 같습니다. 'socketpair()'에 의해 반환 된 소켓과 마찬가지로, 이러한 유형의 소켓은 어떤 경로에도 바인딩되지 않지만 그럼에도 불구하고 다른 끝에있는 다른 소켓에 연결됩니다. – Celada

답변

4

정말 대답이 확실하지 않습니다. 아마 그것은 독서 중에 가치가 있을지 모르지만 일부 연구에 대한 생각과 같을 것입니다.

accept(2)으로 채워진 값은 적어도 Linux 3.16.0, NetBSD 6.1.4 및 Darwin 13.1.0 커널에서 상당히 프로토콜에 무관심한 것으로 보입니다. 실제로 이것은 두 번째 매개 변수 accept(2), struct sockaddr *이 모든 프로토콜간에 공유되는 것으로 만 채워진다는 것을 의미합니다. 따라서 성공적인 acccept(2) 이후에 손에 가지고있는 것은 완전한 struct sockaddr_un과는 거리가 멀습니다.

아마 accept(2)의 첫 번째 구현이 완료되었을 때 그다지 중요하지 않다고 생각한 사람은 아무도 없을 것입니다. 이제는이 문제에 봉착했습니다. 다행스럽게도 이것에 대한 방법이 있습니다. 소켓에 사용 된 경로명을 bind(2)으로 잃어 버렸고, 이제 그것을 다시 찾고 싶습니다.

struct sockaddr_storagegetsockname(2)으로 멤버 sun_path에 액세스 할 수 있습니다. 그래서, 당신이 모든 수분이 많은 세부 사항을 얻고있다 만들 accept(2)에 성공적으로 호출 후 getsockname(2) 전화 (이것은 당신의 server.c에 줄 번호 (40) 이후에 넣을 것) :

 struct sockaddr_storage ss; 
     socklen_t sslen = sizeof(struct sockaddr_storage); 
     if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) { 
       struct sockaddr_un *un = (struct sockaddr_un *)&ss; 
       printf("socket name is: %s\n", un->sun_path); 
     } 

또는 그냥 사용

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#define NAME "socket" 

int main(int argc, char **argv) 
{ 
    int sock, msgsock, rval; 
    struct sockaddr_un server, client; 
    char buf[1024]; 

    sock = socket(AF_UNIX, SOCK_STREAM, 0); 
    if (sock < 0) { 
     perror("opening stream socket"); 
     exit(1); 
    } 

    server.sun_family = AF_UNIX; 
    strcpy(server.sun_path, NAME); 

    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) { 
     perror("binding stream socket"); 
     exit(1); 
    } 

    printf("Socket has name %s\n", server.sun_path); 
    listen(sock, 5); 

    for (;;) { 
     socklen_t len = sizeof(client); 
     msgsock = accept(sock, (struct sockaddr *)&client, &len); 

     if (msgsock == -1) 
      perror("accept"); 
     else do { 
      printf("strlen(sun_path) = %zu\n", strlen(client.sun_path)); 

      struct sockaddr_storage ss; 
      socklen_t sslen = sizeof(struct sockaddr_storage); 
      if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) { 
        struct sockaddr_un *un = (struct sockaddr_un *)&ss; 
        printf("socket name is: %s\n", un->sun_path); 
      } 

      bzero(buf, sizeof(buf)); 
      if ((rval = read(msgsock, buf, 1024)) < 0) 
       perror("reading stream message"); 
      else if (rval == 0) 
       printf("Ending connection\n"); 
      else 
       printf("-->%s\n", buf); 
     } while (rval > 0); 

     close(msgsock); 
    } 
    close(sock); 
    unlink(NAME); 

    return 0; 
} 

이것은 테스트를 거쳤습니다. 커널 3.16.0을 실행하는 GNU/Linux 시스템, 6.1.4 커널을 실행하는 NetBSD 시스템 및 13.1.0 커널을 실행하는 OS/X Mavericks가 장착 된 시스템에서 컴파일 및 예상 결과를 생성합니다. accept(2)의 모든 동작에서 일관성이 있습니다 : sun_path은 채워진 구조에서 찾을 수 없습니다. getsockname(2)의 동작은 다른 운영 환경간에 일관성이 있으므로 모든 프로토콜 관련 세부 정보를 사용할 수 있습니다.

0

클라이언트 소켓을 주소에 바인딩하지 않았습니다.

connect()가 작동하려면 클라이언트 소켓을 주소에 바인드 할 필요가 없습니다. 그러나 서버의 클라이언트 주소에 액세스하려는 경우 bind()를 수행해야합니다.

의미가 있습니까?

클라이언트에 연결하기 전에 bind()를 호출하기 만하면됩니다. 클라이언트가 사용하는 경로가 유효한지 확인하고 정상적으로 오류를 확인하십시오.