2009-05-05 2 views
1

난 그냥이 같은 기능을 가지고 : 넷 링크를 사용하여 커널 공간에서 메시지를 수신에 사용되는리눅스 소켓 프로그래밍 디버그?

static int 
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr, 
    socklen_t *addrlen) 
{ 
    struct timeval timeout = {1, 0}; 
    fd_set set; 
    int status; 

    FD_SET(sock, &set); 
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) { 
     FD_ZERO(&set); 
     fprintf(stderr, 
      "timeout while receiving answer from kernel\n"); 
     exit(1); 
    } else if (status == -1) { 
     FD_ZERO(&set); 
     perror("recvfrom failed"); 
     exit(1); 
    } 
    FD_ZERO(&set); 
    return recvfrom(sock, buf, len, 0, addr, addrlen); 
} 

. 그러나 내가 그것을 실행할 때 결과는 항상 "커널에서 응답을 기다리는 동안 시간 초과"라는 메시지를 소스 코드에서 말합니다. 이는 "select"메서드가 항상 '0'을 반환하는 이유 때문입니다. 나는 이유를 알지 못한다. 누가 나에게 몇 가지 제안을 할 수있다. 고마워.

+0

어쩌면 소켓을 만든 방법에 문제가 있습니까? 소켓에 바인딩 되었습니까? netlink 용 소켓을 만들려면 socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 바인드하려면 구조체 sockaddr_nl 및 멤버 nl_family = AF_NETLINK가있는 주소를 지정해야합니다. –

+0

예, 당신이 말한대로해야합니다. –

+0

먼저 recvfrom하고 잘 작동하도록하십시오. 일단 당신의 소켓이 잘 작동하고 있다고 확신한다면 당신이 선택한 것을 – shodanex

답변

1

FD_SET (양말, & 세트) 전에 FD_ZERO (& 세트)를 설정해야합니다. 그렇지 않으면 fd_set이 초기화되지 않고 많은 세트 비트를 포함 할 것입니다. 또한 종료하기 전에 FD_ZERO()는 상당히 의미가 없습니다.

+0

라고 말한 이유는 아닙니다, 당신의 지시에 따라 코드를 변경했습니다,하지만 작동하지 않습니다, 모두 똑같은 감사합니다. –

0

커널 공간에서 내 코드를 조사했는데 커널이 클라이언트의 메시지 "skb_dequeue (&sk-> sk_receive_queue)"를 사용하여 메시지를 수신 할 수 없음을 알고 있습니다. 나는 어떻게되는지 모른다.

+0

답변이 아니어야합니다. 질문에 대한 수정 사항이어야합니다. – ffledgling

0

처음에는 시간 초과가 발생할 때 strerror(errno) (errno 인쇄 또한 현명함)을 인쇄하여 실제 오류가 무엇인지 알 수 있습니다.

errno가 없을 때 문제가 무엇인지 추측 할 때, 읽을 내용이 있다는 보장은 없습니다. accept (2)를 통해 소켓을 얻었더라도 설정 한 연결 일 수도 있지만 클라이언트가 쓰는 일에 익숙하지 않았을 수도 있습니다. 일반적으로 단 하나의 select (2)를 수행하지 않습니다. 프로그램이 종료되기를 기다릴 때까지 select (2)를 계속 호출하는 단일 메인 루프를 원한다. 시간 제한은 거의 언제든지 어떤 이유로 든 발생할 수 있기 때문이다.

다른 가능한 문제 :

  • 클라이언트는 연결할 수 없습니다.
  • 소켓을 올바르게 바인딩하지 못했습니다.
  • bind (2)를 호출 한 후 서버 소켓에서 listen (2)를 호출하는 것을 잊어 버리는 것입니다.

IP 소켓을 사용하는 경우 Wireshark를 사용하여 네트워크 트래픽을 살펴보고 클라이언트가 예상 한대로 작동하는지 확인할 수 있습니다.

+0

오류가 아니며 시간 초과이므로 errno가 설정되지 않을 것이라고 생각합니다. – shodanex

4

찰리,
몇 가지가 : FD_ISSET()는 파일 기술자에 true를 돌려주는 경우

1) 당신은 아마 당신의 선택() 호출 주위 루프는 만에 recvfrom을 호출해야합니다.
2) netlink 소켓에서 보내는 실제 드라이버 나 커널 코드가 실제로 데이터를 쓰거나 보내고 있는지 확인하십시오. 그렇지 않으면 1 초 안에 데이터를받지 않으면 함수가 시간 종료됩니다. (그것은 당신이 타임 아웃을 설정 한 것이다).

몇 가지 일반적인 의견 ... Linux에서는 select() 시스템 호출을 사용할 때. 시간 초과 데이터 구조는 각 호출 후에 재설정됩니다. 따라서 코드를 변경하여 선택 주위를 반복하면 루프에서 모든 반복에 대한 시간 초과 값을 재설정해야합니다.

또한 선택 시간이 초과되면 오류 일 수 있습니다. 선택은 비 차단 호출임을 기억하십시오. 주어진 'timeout'기간 동안 소켓에서 기다렸다가 돌아올 것입니다. 당신이 무엇이든 상관없이 파일 기술자로부터 읽기를 원한다면 ...recv_kern() 함수가 반환 할 데이터가있을 때까지 차단하고 select()를 사용하지 않아도된다는 것을 의미합니다. 파일 설명자에서 직접 recvfrom()을 호출하면됩니다. 이렇게하면 recv_kernel() 함수가 차단되고 커널이 보낸 데이터를 읽은 후에 만 ​​반환됩니다.


이 코드의 사용 방법에 대한 자세한 내용을 알지 못하면 여기에 좀 더 구체적인 도움을주기가 어렵습니다. 나는 이것이 사용자 공간까지 데이터를 보내는 작성한 사용자 정의 커널 모듈이라고 가정합니다. 맞습니까?
recv_kern() 함수를 변경하여 코드를 선택하고 recvfrom()을 호출하십시오. 이 방법은 커널 드라이버가 실제로 사용자 공간까지 데이터를 제대로 보내고 있는지 알 수 있어야합니다. recvfrom()에서 블로킹하고 모든 것이 돌아 오지 않으면 커널 드라이버에 문제가있을 수 있습니다.

희망이 있습니다.

+1

귀하의 대답은 위의 질문과 관련이없는 소켓 문제로 인해 도움이되었습니다. –

2

당신은이 같은 기능을 재 작성해야 다른 사람이 말했듯이

static int 
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr, 
    socklen_t *addrlen) 
{ 
    struct timeval timeout = {1, 0}; 
    fd_set set; 
    int status; 

    FD_ZERO(&set); 
    FD_SET(sock, &set); 
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) { 
     fprintf(stderr, 
       "timeout while receiving answer from kernel\n"); 
     exit(1); 
    } else if (status < 0) { 
     perror("recvfrom failed"); 
     exit(1); 
    } 
    if ((status = recvfrom(sock, buf, len, 0, addr, addrlen)) < 0) { 
     perror("recvfrom error"); 
     exit(1); 
    } 
    if (status == 0) { 
     fprintf(stderr, "kernel closed socket\n"); 
     exit(1); 
    } 
    return status; 
} 

을, 당신은 선택 호출하기 전에 FD_ZERO를 호출해야합니다. FD_ZERO에 대한 다른 호출은 불필요합니다. 또한 전체 오류 검사를 수행해야합니다.