Форум русскоязычного сообщества Ubuntu


Хотите сделать посильный вклад в развитие Ubuntu и русскоязычного сообщества?
Помогите нам с документацией!

Автор Тема: пара вопросов по сокетам  (Прочитано 629 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн dronte

  • Автор темы
  • Любитель
  • *
  • Сообщений: 98
    • Просмотр профиля
пара вопросов по сокетам
« : 15 Март 2014, 00:33:06 »
Зачастил я тут что-то задавать вопросы последнее время ;D
Ну чтож, начнем.
1) Ситуация такая, слушается неблокирующий сокет, нормально accept-ится и отпочковывается в новый поток, потом снова слушается select-ом, потом accept-ится, но вот проблема, вроде как неблокировка не должна наследоваться, но вот беда, первый раз получается обычный блокирующий сокет, а второй раз - по причине возвращения из recv -1 понимаю, что почему-то он неблокирующий, думал думал, решил попробовать сделать его блокирующим, но вот беда, флаг O_NONBLOCK в природе существует, а вот флага O_BLOCK нет, как быть?
ну или ... на крайний случай помогите разобраться с тем, как получить данные из неблокирующего сокета, ну и соответственно, как считать, по крайней мере у меня почему-то после select вызов recv ничего не дает.
2) inet_ntoa результат раз от раза меняется, то нормально, а то 0.0.0.0 с чем может быть связано и как можно получить нормальный адрес клиента?

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 2248
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #1 : 15 Март 2014, 13:26:39 »
Флаг можно установить или сбросить с помощью fcntl, вот пример из Интернета
flags = fcntl(sg_fd, F_GETFL)
fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
Пётр.

Оффлайн dronte

  • Автор темы
  • Любитель
  • *
  • Сообщений: 98
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #2 : 15 Март 2014, 21:02:35 »
Ого, спасибо огромное! не знал, что так можно сбрасывать флаги!

UPDATE: увы не помогает, поставил даже специально перед каждым recv, толку ноль
« Последнее редактирование: 15 Март 2014, 21:47:03 от dronte »

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 2248
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #3 : 15 Март 2014, 23:23:29 »
Значит, причина в другом. Сам я с сокетами на этом уровне дела не имел,
только в Qt.
Насчёт установки флага в этом случае я прочитал в "man socket",
посмотрите его и "man recv" внимательнее, м.б. и найдёте решение.
Пётр.

Оффлайн dronte

  • Автор темы
  • Любитель
  • *
  • Сообщений: 98
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #4 : 16 Март 2014, 14:56:00 »
нет, проблема именно в блокировке, код

flag = fcntl (ARG->_sock, F_GETFL);
fcntl (ARG->_sock, F_SETFL, flag & (~O_NONBLOCK));
flag = fcntl (ARG->_sock, F_GETFL);
if (flag & O_NONBLOCK) printf ("Yes1\n");

выдает на выходе печать этого тестового сообщения

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 2248
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #5 : 16 Март 2014, 18:00:28 »
Т.е. флаг не сбросился. Тогда проверьте значение, возвращаемое fcntl
после попытки сброса, с помощью errno.

Вообще странно, что возникают проблемы с чтением оиз сокета,
вы же используете select. Можно было попробовать pselect.
 
Пётр.

Оффлайн dronte

  • Автор темы
  • Любитель
  • *
  • Сообщений: 98
    • Просмотр профиля
Re: пара вопросов по сокетам
« Ответ #6 : 19 Март 2014, 00:06:56 »
в связи с тупиком немного отошел просто от темы, поэтому не был тут два дня, значит так, к настоящему моменту, дописал небольшой кусок, который пытается заблокировать сокет, если блокируется, переходит сразу к получению сообщения, если нет, вызывается select и потом опять же к принятию сообщения, при подключении 1-го клиента все происходит нормально, сокет пишет, что заблокирован и запросы обрабатываются, когда подключается второй клиент, то заблокировать сокет не удается и вызывается select, в который все и уходит с концами, при наличии отправленных сообщений от клиента,

кусок кода отвечающий за создание нового процесса выглядит так:
printf ("INFO: listener ... \n");
int ident, res, flag;
thread_arg *arg;

ident = list.AddNode ();
arg = list.GetRecord (ident);
if (arg == 0) {
     printf ("[ERROR] Create Node for new thread!\n");
     // ~~~~~!!!!!~~~~~
}
arg->_listener = listener;
arg->_sock = accept (listener, (struct sockaddr*)&(arg->_addr), &(arg->_len));
flag = fcntl (arg->_sock, F_GETFL);
fcntl (arg->_sock, F_SETFL, flag & (~O_NONBLOCK));
flag = fcntl (arg->_sock, F_GETFL);
if (flag & O_NONBLOCK) printf ("Yes\n");
printf ("%-6d %-15s:%-4d\n", ident, inet_ntoa(arg->_addr.sin_addr), ntohs(arg->_addr.sin_port));
arg->ident = ident;
res = pthread_create(&(arg->thread), 0, thread_server, arg);
if (res != 0) {
     perror("pthread_create");
     close (arg->_sock);
     //printf ("pthrres != 0\n");
     // ~~~~~!!!!!~~~~~
} else {
     printf ("INFO: New thread has been created ...\n");
}
list.UNLockMutex(ident);

кусок кода внутри созданного процесса, отвечающий за начало работы:

FD_ZERO (&rfds);
FD_SET (ARG->_sock, &rfds);
FD_ZERO (&afds);
FD_SET (ARG->_sock, &afds);

flag = fcntl (ARG->_sock, F_GETFL);
fcntl (ARG->_sock, F_SETFL, flag & (~O_NONBLOCK));
flag = fcntl (ARG->_sock, F_GETFL);
if (flag & O_NONBLOCK) {
    printf ("Yes0\n");
    if (select (2, &rfds, 0, 0, 0) < 0) {
         perror("thread select");
         //pthread_cleanup_pop(1);
         pthread_exit(arg);
         return 0;
    }
    printf ("select getten\n");
} else printf ("No0\n");
if (recvall (ARG->_sock, ARG->_user, 64, 0) == -1) printf ("!!ERROR!! recv returned -1\n");
//puts ("\e[1;33;4;44m");
printf ("%s", ARG->_user);
//puts ("\e[0m");
printf (": logon (%u thread)\n", ARG->ident);
//pthread_testcancel();
while (cycle) {
     printf ("%d: while ... ", ARG->ident);
     fflush (stdout);
     flag = fcntl (ARG->_sock, F_GETFL);
     fcntl (ARG->_sock, F_SETFL, flag & (~O_NONBLOCK));
     flag = fcntl (ARG->_sock, F_GETFL);
     if (flag & O_NONBLOCK) {
          printf ("Yes1\n");
          FD_ZERO(&rfds);
          memcpy (&rfds, &afds, sizeof(afds));
          if (select (2, &rfds, 0, 0, 0) < 0) {
               perror("thread select");
               //pthread_cleanup_pop(1);
               break;
               //return 0;
          }
          printf ("select getten\n");
     } else printf ("No1\n");
     recvall (ARG->_sock, (char*)&ihead, sizeof(struct head_of_packages_info), 0);
     /// дальше код анализа
}
код функции recvall:
int recvall (int s, char *buf, int len, int flags) {
        int total = 0;
        int n;

        while(total < len) {
                errno = 0;
                n = recv(s, buf+total, len - total, flags);
                if(n == -1) { break; }
                total += n;
        }
        //printf ("s = %d total = %d n = %d errno = %d\n", s, total, n, errno);
        return (n==-1 ? -1 : total);
}

вывод сообщений сервера:
INFO: connection has been gotten ...
INFO: listener ...
1      0.0.0.0        :0   
INFO: New thread has been created ...
No0
client: logon (1 thread)
1: while ... No1
recieved
1: Create ...
1: while ... No1
recieved
1: Exit ... type = 3072
client: logoff (by 1 thread)
INFO: connection has been gotten ...
INFO: unlist ...
INFO: input == THREAD_EXIT
INFO: Thread ident = (real 1 / arg 1) from (amount = 1 / max = 1) threads has been exited
INFO: connection has been gotten ...
INFO: listener ...
1      127.0.0.1      :37277
INFO: New thread has been created ...
No0
qwerty: logon (1 thread)
1: while ... No1
recieved
1: Create ...
1: while ... No1
recieved
1: Clean ...
1: while ... No1
INFO: connection has been gotten ...
INFO: listener ...
Yes
2      193.13.2.0     :0   
INFO: New thread has been created ...
Yes0

как можно видеть, сначала подключается клиент "client", успешно проводит операции и отключается, потом подключается другой клиент "qwerty", проводит операции, приостанавливает операции (ну просто консольный клиент в другом окне запущен, смысла особого что-то вводить нет, но все запросы выполняются, если ввести), но не отключается, теперь подключается еще один клиент, т.к. теперь одновременно два клиента, то первая цифра в сообщениях, отвечающая за то, кто сделал запрос, становится 2, основной сервер выводит, что поток создан, а потом уже сам поток выводит сообщение о том, что сокет не заблокирован, из того куска кода который выше, переходит потом как по коду видно в селект и зависает, хотя на входе есть сообщения от подключившегося клиента. кстати да, тут на листинге видна ошибка определения ip адресов, хотя клиент подключался всегда через петлю, т.е. 127.0.0.1, использование внешнего ip ситуацию не меняет.

данный листинг работы программы продемонстрирован с целью показать, что если клиенты работают поочереди (т.е. новый не подключается, пока уже подключившийся не отключится), то проблем не возникает.
« Последнее редактирование: 19 Март 2014, 00:30:37 от dronte »

 

Страница сгенерирована за 0.074 секунд. Запросов: 24.