• XSS.stack #1 – первый литературный журнал от юзеров форума

socket клиент передает лишние данные в момент коннекта

gliderexpert

CPU register
Забанен
Регистрация
17.02.2021
Сообщения
1 440
Решения
1
Реакции
2 336
Пожалуйста, обратите внимание, что пользователь заблокирован
Специалисты по Сям, надоумьте где почитать про следующий момент.
Есть сокет сервер на локалхосте.
Открываю к нему коннект обычной командой telnet localhost 7777 . В wireshark вижу один пакет данных от клиента к серверу, в серверной части срабатывает
accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) ;
и дальше процесс останавливается, как и должно быть - в ожидании данных от сокет клиента.

Но, если я создаю сокет клиент на сях, простейшим методом типа

Код:
 if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("socket failed");
                exit(EXIT_FAILURE);
    }
    else{
        printf("socket ready");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(TCP_ADDR);
    address.sin_port = htons(PORT);

    if ( connect(client_fd, (struct sockaddr*)&address, addrlen))   {
        printf("connect error? \n");
    }
     else
         {
    printf("connected \n");
          }


Коннект с этого модуля вызывает генерацию 3 пакетов данных для сервера, и естественно сокет сервак помимо accept'а получает на вход некий мусор. Хотя никаких данных я не отправляю, просто открываю соединение.
Почему так?
Подозреваю что есть некий буфер в сокет клиенте который нужно очищать перед connect'ом к серверу, но как это сделать? В описании к либе <sys/socket.h> особых подробностей нет.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
естественно сокет сервак помимо accept'а получает на вход некий мусор
Это вы выяснили read'ом ?
3 пакетов данных для сервера
Похоже на обычный хэндшейк. https://ru.wikipedia.org/wiki/Transmission_Control_Protocol
Почему с телнетом нет такого большой вопрос. Сравните флаги в пакетах с википедией. (пункт установка соединения)
WSAStartup делаешь ?
Он под линукс пишет, какой WSAStartup??
 
Пожалуйста, обратите внимание, что пользователь заблокирован
может указать IPPROTO_TCP ?
SOCK_STREAM уже достаточно, чтобы это был tcp
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Это вы выяснили read'ом ?

valread = read(new_socket, buffer, 1024);
При первом коннекте от си клиента, оно срабатывает и в буфере мусор. Дальше все работает нормально.
А если телнетом подключаться (не передавая потом ничего), то read не выполняется и буфер соответственно пустой. Но если что-то напечатать в телнет то данные успешно оказываются в буфере,

Плюс эти лишние пакеты видны wireshark'ом.

Похоже на обычный хэндшейк. https://ru.wikipedia.org/wiki/Transmission_Control_Protocol
Почему с телнетом нет такого большой вопрос.

Вот это наверно основной вопрос, почему у телнета более простой хендшейк и чем он отличается от "дефолтного" сокета.


Сравните флаги в пакетах с википедией. (пункт установка соединения)
Да, спасибо - сейчас буду разбираться.

Нет такого ничего, это глюки у тебя или кинь полный код сервера.
Понятно что глюки, вопрос как их найти и исправить.
Обычный сервер, ничего интересного. Из примеров с сайта IBM.

C:
 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
     printf("socket failed");
     exit(EXIT_FAILURE);
    }
    else{
        printf("socket ready");
    }

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,  sizeof(opt)))
    {
      printf("setsockopt");
      exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(TCP_ADDR);
    address.sin_port = htons(PORT);
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        printf("bind failed");
        exit(EXIT_FAILURE);
      }
    if (listen(server_fd, 3) == 0)
    {
        printf("Listening \n");
    }
    if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen))  < 0) {
        printf("accept error?");
    }
  valread = read(server_fd, buffer, 1024);
  printf("read\n");

В случае коннекта от телнет - выполняется строго до строки printf("Listening \n");
telnet.png



, а если подключиться из проги на си - то до строки printf("read\n"); и в buffer'е мусор.
c client.png

В общем часть проблемы решил, все оказалось просто - у меня в c клиенте после connect'а и "отладочного" printf больше ничего не было.
Соответственно, клиент после отработки коннекта - закрывался. Но перед этим зачем-то посылал еще команду FIN, закрывая соединение с сервером.
Если в конце клиента добавить какой нибудь while(1) то все работает как и с телнетом.

Вот эти приколы в стиле python'а я честно говоря не люблю и продолжу разбираться - почему он закрывает порт при выходе из проги, если я в явном виде не давал такую команду? Или это в таком случае делает сама система? Да, речь про linux конечно же.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
закрывает порт при выходе из проги, если я в явном виде не давал такую команду? Или это в таком случае делает сама система?
Достоверного ответа не дам, но мне кажется тут такая же логика, как и с дескрипторами файлов.
Когда вы открываете файл через fopen, то вам возвращается FILE* (дескриптор файла) . И этот файл будет открыт (то есть деcкриптор будет валиден), пока не будет закрыта программа или не будет вызван fclose(FILE*).
С сокетами всё тоже самое. Вы получаете дексриптор сокета после вызова int socket(int domain, int type, int protocol);
И дескриптор закроется при выходе из проги или при вызове close(int). (кстати в доке на close написано, что это функция для закрытия file descriptor, что наводит на определённые мысли по поводу сокета, и что "Всё в линукс файл")
Так что да, при выходе без вызова close система сама закроет дескриптор и коннект упадёт.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Похоже что так и есть, спасибо большое всем!
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Вообще, я бы лично посоветовал перейти на сокеты буста, во первых они кроссмплатформенные, во вторых они очень просты в использовании
Так в винапи и в линуксах одни и те же функции для работы с сокетами. Просто нужно инклюды другие делать и WSAStartup() WSACleanup() вызывать на винде.
Всё это решается парочкой #ifdef'ов и тянуть огромный буст для этого это бред. Да и стандартные сокеты не сказать, что сложны в использовании.
Плюс есть предположение, что ТС делает не совсем белый софт и буст ему "в хер не упёрся") Но это уже не имеет отношения к выше сказанному.
 
Сокеты вообще в винду перекочумали из Unix. Перед WSACleanup() желательно загасить сокет: shutdown(); close();
 
Так в винапи и в линуксах одни и те же функции для работы с сокетами. Просто нужно инклюды другие делать и WSAStartup() WSACleanup() вызывать на винде.
Всё это решается парочкой #ifdef'ов и тянуть огромный буст для этого это бред. Да и стандартные сокеты не сказать, что сложны в использовании.
Плюс есть предположение, что ТС делает не совсем белый софт и буст ему "в хер не упёрся") Но это уже не имеет отношения к выше сказанному.
совет - это не принуждение) у каждого свой выбор
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Какой буст - у меня весь лоадер 12кб весит, и еще есть куча возможностей оптимизации. Но за совет спасибо )
 
Пожалуйста, обратите внимание, что пользователь заблокирован
совет - это не принуждение) у каждого свой выбор
Какой буст - у меня весь лоадер 12кб весит, и еще есть куча возможностей оптимизации. Но за совет спасибо )
Ну кстати на сервере мб юзать можно, но честно говоря не вижу особого преимущества над обычными сокетами
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх