Windows CE5.0 socket... ТЕМА ЗАКРЫТА выбрано иное решение

Тема в разделе "Флудилка", создана пользователем Igor68, 2 окт 2018.

  1. Igor68

    Igor68 Гуру

    Имеется устройство с этой ОС... сделана система автоматики по ModbusRTU, где ведущим это устройство. Всё нормально... но это устройство ещё и в сети. Некая программа на другом ПК подключается к этому серверу для чтения данных и проверки работоспособности как по написанному коду так и по NetCat для проверки работоспособности сервера. Кроме того другая программа-скрипт по telnet обращается к этому устройству для реализации его перезапуска. Ну и т.п.
    И вот проблема:
    Код (Text):
    \> netstat -nlta

    TCP TABLE
                Loc Addr   Loc Port             Rem Addr   Rem Port State
                 0.0.0.0         21              0.0.0.0        139 LISTEN
                 0.0.0.0         23              0.0.0.0      57449 LISTEN
                 0.0.0.0         80              0.0.0.0      20725 LISTEN
                 0.0.0.0        135              0.0.0.0       4326 LISTEN
                 0.0.0.0        139              0.0.0.0      24784 LISTEN
                 0.0.0.0        443              0.0.0.0      24612 LISTEN
                 0.0.0.0        987              0.0.0.0      33016 LISTEN
                 0.0.0.0       2394              0.0.0.0      24806 LISTEN
                 0.0.0.0       2395              0.0.0.0      28683 LISTEN
                 0.0.0.0       5120              0.0.0.0       8263 LISTEN
                 0.0.0.0       9891              0.0.0.0      24641 LISTEN
               127.0.0.1       3001              0.0.0.0      37081 LISTEN
           192.168.1.210         23        192.168.1.110      51446 ESTAB
           192.168.1.210         23        192.168.1.110      51448 ESTAB
           192.168.1.210         23        192.168.1.110      51706 ESTAB
           192.168.1.210        445              0.0.0.0       8408 LISTEN
           192.168.1.210       3008        192.168.1.100        102 ESTAB
           192.168.1.210       9891        192.168.1.110      40446 CLOSE_WAIT
           192.168.1.210       9891        192.168.1.110      40450 CLOSE_WAIT
           192.168.1.210       9891        192.168.1.110      40454 CLOSE_WAIT
           192.168.1.210       9891        192.168.1.110      40458 CLOSE_WAIT
           192.168.1.210       9891        192.168.1.110      40462 CLOSE_WAIT

    UDP TABLE
                Loc Addr   Loc Port
                 0.0.0.0        137
                 0.0.0.0        137
                 0.0.0.0        138
                 0.0.0.0        161
           192.168.1.210       5048
    \>
     
    Это консоль устройства, а CLOSE_WAIT могут висеть и неделю... и может и дольше. Это после подключения и отключения клиента, а так же после обращений по NetCat по порту 9891. Сокет висит пожизненно. Вот поток обслуживания клиента (в VisualSudio 2005 для Windows CE):
    Код (C++):
    void __stdcall ServerProcess(SERV *dat)  
    {
        SERV s_dat;
        int res;
        int cntlive = _time_live;
        U8    InBuf[_srsizebuf];
        U8    OutBuf[_srsizebuf];
        U8    flagSend;
        memcpy((void*)(&s_dat),(void*)(dat),sizeof(SERV));
        memset((U8*)(&OutBuf[0]),0,_srsizebuf);
        //setsockopt(s_dat.Socket[s_dat.CurrentNumClient],0,11,11,11);
        while(1)
        {
            //===== ожидание мьютекса ======
            while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
            {
                Sleep(_SSLEEP);
            };
            //printf("==server== %i\r\n", s_dat.socket);
            memset((U8*)(&InBuf[0]),0,_srsizebuf);
            memset((U8*)(&OutBuf[0]),0,_srsizebuf);
            res = ReadSocket(s_dat.Socket[s_dat.CurrentNumClient], &InBuf[0]);
            flagSend = 0;
            switch(res)
            {
                case -2:
                    goto err; //выход при ошибке чтения
                default:
                    //анализ типа пакета
                    switch((U8)(InBuf[_ad_pkt]))
                    {
                        case _PKT_NULL:
                            (*(U16*)(&OutBuf[_ad_size])) = _size_null;
                            OutBuf[_ad_pkt] = _PKT_NULL;
                            flagSend = 0xFF;
                            break;
                        case _PKT_REAL:    //пакет реальных данных
                            (*(U16*)(&OutBuf[_ad_size])) = _size_null + sizeof(SDAT);//(RdReal(&OutBuf[3]));
                            memcpy(&OutBuf[3], &sdat, sizeof(SDAT));
                            OutBuf[_ad_pkt] = _PKT_REAL;
                            flagSend = 0xFF;
                            break;
                        default:            //неизвесный пекет
                            break;
                    }
            }
            //
            if(flagSend > 0)
            {
                res = WriteSocket(s_dat.Socket[s_dat.CurrentNumClient],&OutBuf[0],(*(U16*)(&OutBuf[_ad_size])));
                switch(res)
                {
                    case -2:
                        goto err; //выход при ошибке записи
                    case -1:
                        break;
                    default:
                        cntlive = _time_live;
                        break;
                }
            }
            if(cntlive < 0)
                goto err; //время жизни вышло
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
            Sleep(_serv_pr_ssleep);
            cntlive -= _serv_pr_ssleep;
        }
    err:    printf("==stop server=\r\n");
            shutdown(s_dat.Socket[s_dat.CurrentNumClient], 2);
            while( recv(s_dat.Socket[s_dat.CurrentNumClient], &InBuf[0], _srsizebuf, 0)!= -1);
                closesocket(s_dat.Socket[s_dat.CurrentNumClient]);
            dat->Socket[s_dat.CurrentNumClient]    = 0;
            dat->CntClient--;
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
    }
     
    Не ругайте за код... он изменяется и сейчас... сию минуту.
    Уже недели 2 с этим ковыряюсь...
    С Linux всё проще и работает. Никого не хочу обидеть, но от Microsoft ничего хорошего уже давно не ожидаю.
    А "заплатки" невозможно прикрутить и нет их... система в прошивке устройства.
    С глубоким уважением!
     
  2. Igor68

    Igor68 Гуру

    ...что-то полазил по поисковикам... и там тысячи таких вопросов на эту тему. Конечно там обычный windows, который можно обновлять. И пока не знаю как быть... делать на сторонней машине с Linux жесточайший контроль за Windows(она сейчас занимается сбором данных, и на неё навешано много ещё других задач) ... скриптами по доступа к устройству или можно по нормальному с закрытием сокета. Если по нормальному, то переделать только одну программу с набором dll, а если контроль то надо переделать много уже готового. Было бы проще это предоставить другой машине, если бы эта была бы локальная сеть предприятия, а не другая сеть к оборудованию, в которой нет иных машин.
    Может по нормальному Microsoft и решил уже эту проблему через несколько лет... но вот я пока только в настоящем времени и немного помню прошлое...
     
  3. Mitrandir

    Mitrandir Гуру

    А кто сокет открывает? Пусть он и чистит за собой
     
  4. SergeiL

    SergeiL Гуру

    А как поток завершается? Перед этим сокет закрывается?
     
  5. Igor68

    Igor68 Гуру

    Это как?
    Вот стартует сервер:
    Код (C++):
    /*******************************
    СТАРТ СЕРВЕРА
    ********************************/

    int    StartServer(void)
    {
        int timeout;
        //===== ожидание мьютекса ======
        while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
        {
            Sleep(_SSLEEP);
        }
        //==============================
        //======== Initialize Winsock =======
        WSAStartup(MAKEWORD(2,2), &wsaData);
         //======== Create a SOCKET for connecting to server =========
        ListenSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
        //======== Setup the TCP listening socket ===================
    //    int maxbuff = SO_MAX_MSG_SIZE;
    //    setsockopt(SL1_ListenSocket,SOL_SOCKET,SO_RCVBUF, (char*) &maxbuff, sizeof(maxbuff));
    //    setsockopt(SL1_ListenSocket,SOL_SOCKET,SO_SNDBUF, (char*) &maxbuff, sizeof(maxbuff));
        //===========================================================
        timeout = _SOCKET_TIMEOUT;
        setsockopt(ListenSocket,SOL_SOCKET,SO_SNDTIMEO,(char*) &timeout,sizeof(timeout));
        setsockopt(ListenSocket,SOL_SOCKET,SO_RCVTIMEO,(char*) &timeout, sizeof(timeout));
        //===========================================
        ServerAddr.sin_family = AF_INET;
        ServerAddr.sin_addr.s_addr = INADDR_ANY;
        ServerAddr.sin_port = htons(LPort);
        memset(&(ServerAddr.sin_zero), '\0', 8);
        //select(ListenSocket,NULL,NULL,NULL,&tv);
        SL1_err = bind(ListenSocket,(struct sockaddr *) &ServerAddr, sizeof(ServerAddr));
        if(SL1_err == INVALID_SOCKET)
        {
            closesocket(ListenSocket);
            WSACleanup();
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
            //=================================
            return -1;
        }
        SL1_err = listen(ListenSocket,_MaxSock);
        if (SL1_err == SOCKET_ERROR) {
            closesocket(ListenSocket);
            WSACleanup();
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
            //=================================
            return -1;
        }
        /************************************************************
        Запуск потоков сервера
        *************************************************************/

        //===== запуск потока прослушивания ======
        if(serv.ListenWork == FALSE)
        {
            serv.ListenWork = TRUE;
            ListenHnd = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadListenProcess,
                           NULL,NULL,&ListenID);
            SetThreadPriority(ListenHnd,THREAD_PRIORITY_NORMAL);
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
            //=================================
            Sleep(_SSLEEP);
            //===== ожидание мьютекса ======
            while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
            {
                Sleep(_SSLEEP);
            }
            //==============================
        }
        //====== Освобождаем мьютекс ======
        ReleaseMutex(hMutex); //
        //=================================
        return 0;
    }
    тут и создаётся поток прослушивания... вот этот:
    Код (C++):
    /****************************************
    ПОТОК ПРОСЛУШИВАНИЯ СОКЕТА
    *****************************************/

    void __stdcall ThreadListenProcess(void)//(void * arg)
    {
        //HWND hwnd;
        struct sockaddr_in addr;
        int addr_len = sizeof(addr);
        DWORD a = 0;
        WORD count;
        BOOL res1;
        fd_set fds;
        //TimeTick = 0;
        //timeval tv;
        //===== ожидание мьютекса ======
        while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
        {
            Sleep(_SSLEEP);
        };
        //==============================
        do
        {
            //===========реализация выхода по таймауту =============
            tv.tv_sec = 0;                                      
            tv.tv_usec = _SOCKET_TIMEOUT;                                                                          
            FD_ZERO(&fds);                                      
            FD_SET(ListenSocket,&fds);
            //SL1_err = select(SL1_ListenSocket,&fds,NULL,NULL,&tv);
            //SL1_err = WSAAsyncSelect(SL1_ListenSocket,hwnd,WM_SOCKET,FD_ACCEPT | FD_READ);
            SL1_err = select(ListenSocket,&fds,&fds,&fds,&tv);
            //SL1_err = select(SL1_ListenSocket,NULL,NULL,NULL,&tv);
            if(SL1_err == 0)                                      
            {
                //====== Освобождаем мьютекс ======
                ReleaseMutex(hMutex); //
                //=================================
                Sleep(_SSLEEP);
                //===== ожидание мьютекса ======
                while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
                {
                    Sleep(_SSLEEP);
                };
                //==============================
                continue;
            }
            //=====================================================
            ClientSocket = accept(ListenSocket,(struct sockaddr*) &addr, &addr_len);
            //a = addr.sin_addr.S_un.S_addr;
            //=========== поиск записей по адресу в списке =========
            count = 0;
            res1 = FALSE;
            while(count < _MaxSock)    //
            {
                if(serv.Socket[count] == 0)
                {
                    serv.CurrentNumClient    = count;
                    serv.Socket[count]        = ClientSocket;
                    serv.cHnd[count]        = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ServerProcess,
                           &serv, NULL,&serv.cID[count]);
                    serv.CntClient++;
                    break;
                };
                count++;
            }
            //if(!(res1))
            //{
            //    closesocket(ClientSocket);
            //}
        //====== Освобождаем мьютекс ======
        ReleaseMutex(hMutex); //
        //=================================
        Sleep(_SSLEEP);
        //===== ожидание мьютекса ======
        while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
        {
            Sleep(_SSLEEP);
        };
        //==============================
        }while(serv.ListenWork);
        closesocket(ListenSocket);
        WSACleanup();
        //====== Освобождаем мьютекс ======
        ReleaseMutex(hMutex); //
        //=================================
    }
     
    Он принимает входящие соединения и формирует поток для этого соединения - обслуживание клиента. Вот:
    Код (C++):
    void __stdcall ServerProcess(SERV *dat)  
    {
        SERV s_dat;
        DWORD optval;
        int res;
        int cntlive = _time_live;
        U8    InBuf[_srsizebuf];
        U8    OutBuf[_srsizebuf];
        U8    flagSend;
        memcpy((void*)(&s_dat),(void*)(dat),sizeof(SERV));
        while(1)
        {
            //===== ожидание мьютекса ======
            while(WaitForSingleObject( hMutex, _TimeMutex) == WAIT_TIMEOUT)
            {
                Sleep(_SSLEEP);
            };
            //printf("==server== %i\r\n", s_dat.socket);
            memset((U8*)(&InBuf[0]),0,_srsizebuf);
            memset((U8*)(&OutBuf[0]),0,_srsizebuf);
            res = ReadSocket(s_dat.Socket[s_dat.CurrentNumClient], &InBuf[0]);
            flagSend = 0;
            switch(res)
            {
                case -2:
                    goto err; //выход при ошибке чтения
                default:
                    //анализ типа пакета
                    switch((U8)(InBuf[_ad_pkt]))
                    {
                        case _PKT_NULL:
                            (*(U16*)(&OutBuf[_ad_size])) = _size_null;
                            OutBuf[_ad_pkt] = _PKT_NULL;
                            flagSend = 0xFF;
                            break;
                        case _PKT_REAL:    //пакет реальных данных
                            (*(U16*)(&OutBuf[_ad_size])) = _size_null + sizeof(SDAT);//(RdReal(&OutBuf[3]));
                            memcpy(&OutBuf[3], &sdat, sizeof(SDAT));
                            OutBuf[_ad_pkt] = _PKT_REAL;
                            flagSend = 0xFF;
                            break;
                        default:            //неизвесный пекет
                            break;
                    }
            }
            //
            if(flagSend > 0)
            {
                res = WriteSocket(s_dat.Socket[s_dat.CurrentNumClient],&OutBuf[0],(*(U16*)(&OutBuf[_ad_size])));
                switch(res)
                {
                    case -2:
                        goto err; //выход при ошибке записи
                    case -1:
                        break;
                    default:
                        cntlive = _time_live;
                        break;
                }
            }
            if(cntlive < 0)
                goto err; //время жизни вышло
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
            Sleep(_serv_pr_ssleep);
            cntlive -= _serv_pr_ssleep;
        }
    err:    printf("==stop server=\r\n");
            optval = 1;
            setsockopt(s_dat.Socket[s_dat.CurrentNumClient], SOL_SOCKET, SO_LINGER, &optval, sizeof(optval));
            setsockopt(s_dat.Socket[s_dat.CurrentNumClient], SOL_SOCKET, SO_LINGER, &optval, sizeof(optval));
            shutdown(s_dat.Socket[s_dat.CurrentNumClient], 2);
            closesocket(s_dat.Socket[s_dat.CurrentNumClient]);
            /*shutdown(s_dat.Socket[s_dat.CurrentNumClient], 2);
            while( recv(s_dat.Socket[s_dat.CurrentNumClient], &InBuf[0], _srsizebuf, 0)!= -1);
                closesocket(s_dat.Socket[s_dat.CurrentNumClient]);*/

            dat->Socket[s_dat.CurrentNumClient]    = 0;
            dat->CntClient--;
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
    }
    Он работает с клиентом... принимает запросы и отдаёт ответ... структуры данных, с которыми работает основной поток... ну допустим main. А при ошибке связи, разрыве соединения или клиент забыл про обмен... ну завис и т.п. этот поток должен закрыть соединение и умереть. Одновременно может быть создано _MaxSock = 20 потоков т.е. в одно время может быть подключено к серверу 20 клиентов. В их число входят программы сбора данных, скрипт контроля наличия порта(то что сервер в работе) и т.п. Кроме того программа (часть этого сервера тут не показана) является и клиентом, который подключается к контроллеру AC800M для контроля за техпроцессом и ещё по 2-м Modbus RTU контролировать работу насосов охлаждения и управлять ими.
     
  6. Igor68

    Igor68 Гуру

    Да. Вот часть окончания потока:
    Код (C++):
    void __stdcall ServerProcess(SERV *dat)  
    {
        SERV s_dat;
        DWORD optval;
        int res;
        int cntlive = _time_live;
        U8    InBuf[_srsizebuf];
        U8    OutBuf[_srsizebuf];
        U8    flagSend;
        memcpy((void*)(&s_dat),(void*)(dat),sizeof(SERV));
        while(1)
        {
    ......
    ......
    ......
        }
    err:    printf("==stop server=\r\n");
            optval = 1;
            setsockopt(s_dat.Socket[s_dat.CurrentNumClient], SOL_SOCKET, SO_LINGER, &optval, sizeof(optval));
            setsockopt(s_dat.Socket[s_dat.CurrentNumClient], SOL_SOCKET, SO_LINGER, &optval, sizeof(optval));
            shutdown(s_dat.Socket[s_dat.CurrentNumClient], 2);
            closesocket(s_dat.Socket[s_dat.CurrentNumClient]);
            /*shutdown(s_dat.Socket[s_dat.CurrentNumClient], 2);
            while( recv(s_dat.Socket[s_dat.CurrentNumClient], &InBuf[0], _srsizebuf, 0)!= -1);
                closesocket(s_dat.Socket[s_dat.CurrentNumClient]);*/

            dat->Socket[s_dat.CurrentNumClient]    = 0;
            dat->CntClient--;
            //====== Освобождаем мьютекс ======
            ReleaseMutex(hMutex); //
    }
    Как видно мы прыгаем на метку err, потому как мютекс отпускаем в конце. Да и данные для контроля состояния только локальные. Конечно ничего не понял завершения собственно потока(не соединения) именно в windows, когда в Linux всё понятно и однозначно:
    Код (C++):
    pthread_exit(0); //как пример
     
  7. Igor68

    Igor68 Гуру

    Простите меня за беспокойство!!!!!
    Уж надоело уже и по поисковикам и тестировать новый код по схеме:
    VirtualBox(windows, VisualSudio, Проект)<-внутренняя сеть->PC Debian <-локальная сеть->PC_сервер Debian<-сеть оборудования цеха->UNO-1019.
    Проще переделать скрипты автоконфигурации, настройки и контроля на PC_сервер Debian и не морочить голову. А Windows нужен только как рабочая станция... и я дурак полный, что выбрал контроллер с Windows в 2007 году. Сейчас поставили задачу про надёжность, пытался решить, переделать. А что толку? Проще контроль ужесточить. UNO-1019 получает дату и время от рядом стоящего AC800M... а PC_сервер Debian и программа-клиент на нём получает это время от UNO-1019. Так пусть он PC_сервер Debian и перезапускает этого UNO-1019 по telnet. А виндовс умеет работать если только кнопка сброса рядом.
    Извините!