Нет первого запуска адреса с двунаправленным сокетом домена unix

У меня есть два демона (один клиент и один сервер), которые общаются через сокеты домена unix (локальные сокеты). Проблема, с которой я сталкиваюсь, заключается в том, что при первом приеме дейтаграммы сервером с помощью функции recvfrom адрес клиента, предоставленный функцией recvfrom, оказывается пустым. Однако размер предоставленного адреса клиента кажется правильным. Если я увеличу длину адреса (более длинное имя) в клиентском демоне, это отразится на увеличении размера адреса на сервере. Также полученные данные верны.

Обратите внимание, что эта проблема возникает только при первом получении дейтаграммы на сервере. Когда другие дейтаграммы получены, поле адреса правильное.

Есть тут специалисты, которые понимают, что может быть не так?

Код сервера:

static struct sockaddr_un myclient_address;
socklen_t address_length = 0;

int fd;
struct sockaddr_un addr;
struct my_device *dev = dev->device;

fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
  f_warning("socket error");
}

memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;

memset(&myclient_address, 0, sizeof(myclient_address));
myclient_address.sun_family = AF_UNIX;

char *socket_path = "#myserver";
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
addr.sun_path[0] = '\0';

unlink(socket_path);

if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  f_warning("bind error");
}

dev->socket_fd = fd;
dev->socket_io_channel = g_io_channel_unix_new(fd);
dev->socket_io_src_id = g_io_add_watch(dev->socket_io_channel,
                                   G_IO_IN,
                                   socket_in_data_callback,
                                   dev);

static gboolean 
socket_in_data_callback(GIOChannel *source, GIOCondition cond, gpointer     data)
{
  struct my_device *dev = data;
  gsize read_count = 0;
  GIOStatus status;
  guchar* data = g_malloc0(300);
  read_count = recvfrom(dev->socket_fd, (char *) data,  300, 0,
    (struct sockaddr *) &(myclient_address),    &address_length);
  return TRUE;

}

Код клиента:

int fd;

struct sockaddr_un mycli_addr;

fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) {
  f_warning("socket error");
}

memset(&addr, 0, sizeof(addr));
memset(&mycli_addr, 0, sizeof(mycli_addr));
addr.sun_family = AF_UNIX;
mycli_addr.sun_family = AF_UNIX;

char *socket_path = "#myserver";
char *mycli_socket_path = "#myclient";

strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
strncpy(mycli_addr.sun_path, mycli_socket_path, sizeof(mycli_addr.sun_path));
addr.sun_path[0] = '\0';
mycli_addr.sun_path[0] = '\0';

unlink(socket_path);
unlink(mycli_socket_path);

int er;
er = bind(fd, (struct sockaddr*)&mycli_addr, sizeof(mycli_addr));
if (er < 0) {
  f_warning("bind error");
}

if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  f_warning("connect error");
}

session->socket_io_channel = g_io_channel_unix_new(fd);
session->socket_io_src_id = g_io_add_watch(session->socket_io_channel,
                                           G_IO_IN,
                                          client_socket_in_data_callback,
                                           session);

sendto(session->socket, (char *) mydata, data_length, 0,
      (struct sockaddr *) &addr,
      sizeof(struct sockaddr_un));

person ria    schedule 01.09.2015    source источник


Ответы (1)


Я нашел свою ошибку. Я должен был сделать эту инициализацию глобальной переменной длины адреса в коде сервера:

//socklen_t address_length = 0;
socklen_t address_length = sizeof(myclient_address.sun_path);

Потому что address_length является аргументом значения-результата функции recvfrom.

person ria    schedule 07.09.2015