2016-05-03 5 views
1

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

int create_server_unix_socket(const string& socket_path) { 

    // STEP 1 : socket() 
    int unix_socket = socket(AF_UNIX, SOCK_STREAM, 0); 
    if (unix_socket == -1) { 
     throw std::runtime_error {"Error occured in socket() call : "s + 
      string(std::strerror(errno))}; 
    } 

    // STEP 2 : bind(), setup the address structures for bind() 
    sockaddr_un local_address; 
    local_address.sun_family = AF_UNIX; 
    std::strcpy(local_address.sun_path, socket_path.c_str()); 

    // unlink from before 
    unlink(socket_path.c_str()); 

    // STEP 2 : bind() 
    size_t length = socket_path.size() + sizeof(local_address.sun_family); 
    if (::bind(unix_socket, reinterpret_cast<sockaddr*>(&local_address), 
       length) == -1) { 
     throw std::runtime_error {"Error occured in bind() call : "s + 
      string(strerror(errno))}; 
    } 

    // STEP 3 : listen() 
    if (listen(unix_socket, 5) == -1) { 
     throw std::runtime_error {"Error occured in listen() call : "s + 
      string(strerror(errno))}; 
    } 

    return unix_socket; 
} 

Но всякий раз, когда я пытаюсь создать сокет, как так

create_server_unix_socket("./unix_socket"s); 

файл, который создается в текущем рабочем каталоге является unix_socke вместо unix_socket и на самом деле это происходит с любым именем, которое я стараюсь , Если я попробую unix_socket_longer_name, файл будет unix_socket_longer_nam. Я запускаю это на Mac OS X (версия 10.11.4).

Любые идеи о том, что я делаю неправильно? Также, если вы заметили что-то ужасное в моем коде, сообщите мне! Я написал это, посоветовавшись с страницами руководства, и я не совсем уверен, что сделал все правильно. Благодаря!

ПРИМЕЧАНИЕ: Я компилирую это с C++ 14, вам нужно будет импортировать пространство имен std::literals::string_literals, чтобы сделать эту работу. Добавьте using namespace std::literals::string_literals в начало вашего кода.

ответ

2

Давайте посмотрим на человека странице bind

int bind(int sockfd, const struct sockaddr *addr, 
      socklen_t addrlen); 

Третий параметр является addrlen

addrlen определяет размер, в байтах, адрес структуры указал до addr.

Итак, что вы должны проходить, это sizeof local_address. Вместо этого вы прошли length, который socket_path.size() + sizeof(local_address.sun_family). Такого размера почти достаточно, но нет места для нулевого терминатора, и он игнорирует возможность того, что sockaddr_un может содержать отступы.

Если вы действительно хотите, чтобы передать длину, которая соответствует пути, а не полный размер local_address, вы могли бы использовать offsetof:

length = offsetof(sockaddr_un, sun_path) + socket_path.size() + 1; 

Но я не вижу преимущество в этом над простым пропусканием sizeof local_address ,

+0

Я думал, что это была проблема! Я сделал это прямо с man-страниц, но вернулся к моему решению, когда я посмотрел здесь http://beej.us/guide/bgipc/output/html/multipage/unixsock.html, и автор, казалось, использовал длину, которую я использовал в фрагменте кода выше! – Curious

+1

@Curious Я подозреваю, что код, вероятно, зависит от поведения конкретной платформы и может работать в некоторых реализациях. Мое предложение исправить проблему? – user2079303

+0

Да, это так! У меня был другой вопрос, но я думаю, что в ближайшее время я задам этот вопрос. Благодаря! – Curious

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