2013-12-02 2 views
0

Я добавил к домену сокета Unix проект, над которым я работаю. Сокет имеет простую функцию, он просто передает данные, которые извлекает код с другого устройства, идея состоит в том, что другие приложения смогут считывать эти данные из сокета.Ошибка сокета домена Unix домена на встроенном устройстве

Я написал простой код сервера, и когда я запускаю код на своем ноутбуке, используя Ubuntu 10.04 VM, он работает отлично. Однако, когда я копирую код на встроенное устройство, я использую код сбой, когда мое приложение пытается записать в сокет, код выходит.

В /var/log/messages я вижу следующие сообщения:

Dec 2 15:12:17 box local1.info my-app[17338]: Socket Opened 
Dec 2 15:12:17 box local1.err my-app[17338]: Socket Failed 
Dec 2 15:12:17 box local1.err my-app[17338]: Protocol wrong type for socket 
Dec 2 15:12:38 box local1.info ./server[17178]: accept failed: Invalid argument 

Вот код сервера:

#include <stdio.h> 
#include <sys/un.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <errno.h> 
#include<syslog.h> 

#define SV_SOCK_PATH "/tmp/rtig.sock" //path to be used by socket 
#define BUF_SIZE 256 //Max length of string listened to 
#define BACKLOG 5 

int main(int argc, char *argv[]){ 
    struct sockaddr_un addr; 
    int sfd, cfd;  //File Descriptors for the server and the client 
    ssize_t numRead; //Length of the string read from the client. 
    u_int8_t buf[BUF_SIZE]; //String that reads messages 
    char plain[BUF_SIZE]; //Plain string for writing to the log 
    memset(plain, 0, sizeof plain); //blank out plain string 

    openlog(argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); //Write the messages to the syslog 

//---Declare socket-------------------------------------- 
    sfd = socket(AF_UNIX, SOCK_STREAM, 0); 
    if(sfd!=0){ 
    syslog(LOG_INFO, "socket success"); 
    } 
    else{ 
    syslog(LOG_INFO, "socket unsuccessful"); 
    } 

    //--Test to see if there's already a socket at SV_SOCK_PATH, and remove it if there is. 
    if (remove(SV_SOCK_PATH) == -1 && errno !=ENOENT){ 
    syslog(LOG_INFO, "error removing socket"); 
    } 

//----------------------------------------------------------- 

    //--blank out the socket address, then write the information to it 
    memset(&addr, 0, sizeof(struct sockaddr_un)); 
    addr.sun_family = AF_UNIX; 
    strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path)-1); //ensure path is null terminated 

//----Bind the socket to the address------------------------------------- 
    if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un))!=0){ 
    syslog(LOG_INFO, "bind unsuccessful"); 
    } 
    else{ 
    syslog(LOG_INFO, "bind successful"); 
    } 
//------------------------------------------------------------------------ 

//-----Listen on the socket----------------------------------------------- 
    if (listen(sfd, BACKLOG) != 0){ 
    syslog(LOG_INFO, "listen failed"); 
    } 
    else{ 
    syslog(LOG_INFO, "listen succeeded"); 
    } 
//------------------------------------------------------------------------- 

//--------Accept messages on the socket------------------------------------ 
socklen_t csize; 

    while(1){ 

    cfd = accept(sfd, (struct sockaddr *)&addr,&csize); 

    if (cfd < 0) { 
     syslog(LOG_INFO, "accept failed: %s", strerror(errno)); 
    } 

    while ((numRead=read(cfd, buf, BUF_SIZE)) > 0){ 

    dump_packet(buf, numRead); 

    } 

    } 
//------------------------------------------------------------------------- 

//---code never gets here but this is how to close the log and the socket-- 
    closelog(); 
    close(cfd); 
} 

А вот простая версия клиента, который подключается к этому серверу из моего приложения:

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/un.h> 

#define SV_SOCK_PATH "/tmp/rtig.sock" //path to be used by socket 
#define BACKLOG 5 

int isDaemon = 1; 

void etmlog(int level, char *message) 
{ 
isDaemon == 1 ? syslog(level, message) : printf(message); 
} 

int main(){ 
    struct sockaddr_un addr; 
    unsigned int sockfd; 
    ssize_t numRead; 


if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) > 0) { 
    etmlog(LOG_INFO, "Socket Opened\n"); 
} 
    else { 
    etmlog(LOG_ERR, "Socket Failed:\n"); 
    etmlog(LOG_ERR, strerror(errno)); 
    exit(-1); 
} 

memset(&addr, 0, sizeof(struct sockaddr_un)); 
addr.sun_family = AF_UNIX; 
strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path) - 1); // -1 ensures null terminated string 

if (connect 
    (sockfd, (struct sockaddr *)&addr, 
    sizeof(struct sockaddr_un)) == -1) { 
    etmlog(LOG_ERR, "Socket Failed\n"); 
    etmlog(LOG_ERR, strerror(errno)); 
    exit(1); 
} else { 
    etmlog(LOG_INFO, "Socket Connection Successful\n"); 
} 

    while (1){ 
    // some data is read into buf up here 

     if (write(sockfd, buf, rdlen) < 0) { 
     etmlog(LOG_ERR, "Write to Socket Failed:"); 
     etmlog(LOG_ERR, strerror(errno)); 
     } 
    } 

    close(sockfd); 
    return 0; 
} 

Я ценю, что я только что опубликовал много кода для чтения но я был бы очень благодарен, если бы кто-нибудь мог дать мне несколько указаний на это.

+0

Ядро устройства может просто опустить поддержку для сокетов домена Unix. Ядро Linux очень настраивается. Поддержка сокетов домена Unix - это флаг конфигурации, выбираемый во время компиляции. –

+0

Спасибо за предложение, однако я уверен, что ядро ​​поддерживает UNIX-сокеты, поскольку они используются в других приложениях, которые запускаются в системе. – James

+1

Да, они поддерживаются, иначе «socket» потерпит неудачу. –

ответ

5

Вы не используете accept правильно. Третий аргумент должен быть инициализирован размером второго аргумента, так что accept не переполнит его. См. man accept.

+1

В частности, это входной параметр: на входе он содержит максимальную длину адреса одноранговой сети, которую он хочет принять, а на выходе он содержит фактическую длину адреса одноранговой сети. –

+0

Спасибо, я пропустил эту строку, я добавил 'csize = sizeof (addr);' и теперь код работает как на встроенном устройстве, так и на моем ноутбуке. – James

Смежные вопросы