가상 PLC, IdUDPServer UDP 수신 종료시 먹통 해결방법
C++Builder 6.0, INDY 9.0.18
저는 UDP를 그냥 소켓 생성해서... 나름대로 좀 안전하게 한다고...
INDY 사용하지 않았는데...
PLC쪽 프로그램을 해주다 보니... PLC를 늘 가지고 다닐 수도 없고
그래서 아주 간단히 그냥 값만 보려고... 만들었습니다.
헐 그런데 IdUDPServer UDP 수신하다 disconnect하면 먹통....
그래도 그렇게 값을 많이 보는 것도 아니고 잠시 잠시 보는 것이라
그냥 종료하고 다시 실행하고... 이런씩으로 했는데....
오늘 이 INDY 함 잡아보자는 생각에.... 검색도 하고 연구도 하고
해서 알아내었습니다. 짝짝짝.... 별것 아닌데....ㅠㅠ
그리고 혹 PLC 작업하는 분들을 위해 간단하지만 제가 사용하는
간단한 가상 PLC UDP 수신 프로그램 올려드리니 많은 사용바랍니다.
-------------------------------------------------------------------------
올리고 나서... 한번 더 Test 하는 데... 너무 불친절한 프로그램이라는 것을 알았습니다.
어떤 PLC인지도 없고 PORT 바꾸는 데도 없고... ㅋㅋㅋ 제가 그냥 사용하던 것이라...
그래서 좀 수정해서... LS PLC, SIMON PLC UDP 2개 바꾸어 사용할 수 있도록 추가했습니다.
(아~~ 가만 생각하니... 밑에 이진수 출력은 SIMON에 맞추어져 있을 것 같습니다. 원래 이진수 출력
없다가 요근래 붙혔는데.... SIMON과 LS의 HEAD 부분의 길이가 다를 것 같은 데.... 생각안남... 이진수 출력은
24Byte 부터 되어 있을 것인데.... 조금 수정해서 사용하십시오.... 죄송...)
한번 더 Test해 보니 이 프로그램에서 수신시작 , 수신종료는 이제 잘 되는데... 먹통도 되지 않고
Client에서 가상 PLC에 보냈다가 끊었다가 하면 Data가 들어오지 않는 문제가 있네요...
그럭저럭 쓸만한 프로그램 만들려고 하니 이렇게 간단한 것도... 손이 많이 가네요...
Client는 일반소켓으로 만들었는데... 혹 TIdUDPClient로 만들면 접속이 끊기면
TIdUDPServer에서 감지해서 Bindings를 Clear할까? 그래도 문제가 발생할 것 같은 데....
Client가 갑자기 죽으면 자기가 나간다는 것을 알릴 수 없을 것이므로...
IdUDPServer1->ReceiveTimeout = 5000;
이것은 5초 동안 Data가 안들어 오면 Binding을 해제하는 것이 아닌가?
대체 이 놈은 뭐야... 이것 뭐 Indy를 자주 사용하지 않으니...
UDP가 TCP처럼 계속 연결되어 있는 것이 아니기 때문에... 접속이 끊겨도(이 말도 웃기지만, 지속연결방법이 아니므로)
Server가 끊긴 것을 모르는 것이 맞는데.... 끙끙....
Client가 Disconnect 되면 바로 감지하는 TCP처럼 매끄럽게 처리하려면 Client, Server 간의
프로토코을 잘 정의해서 작성해야 할 것 같다.... 하기 싫음...
그리고 현제 UDP에서 나의 작업은 장비와 통신 밖에 없는데 프로토콜을 잘 정의할 것도 없을 것 같고...
간단히 PLC로 전달되는 가상값을 보고 싶을 뿐이므로....
그냥 일정시간마다... 서버를 죽이고 Bindings를 Clear하고 다시 살리고를 1초 동안 계속
하려고 한다. 이 부분을 쓰레드로 만들면 TForm1::IdUDPServer1UDPRead와 문제가 혹 발생할 것 느낌이(충돌)....
그냥 Timer로 하는 것이 안전해 보인다. 그래서 Timer 하나 붙이고...
2초 해도 충분하겠는데... Data를 많이 보내는 것도 아니고 해서.... 그냥 1초로 해서 Bindings를
계속 Clear하게 만들어 버렸습니다......
이제 잘 되는군... Client가 Reconnect해도 먹통없이 잘 수행합니다......
void __fastcall TForm1::IdUDPServer1UDPRead(TObject *Sender,
TStream *AData, TIdSocketHandle *ABinding)
{
//이곳에 Application->ProcessMessages();
//이 Code 들어 있으면 먹통됩니다.
//이런 곳에 위의 것을 넣으면 프로그램 멈춤니다. 위의 이것이 델파이나 빌더에서
//예제해서도 종종 보입니다. 그러므로 적절한 곳에 사용하는 것은 맞는데...
//어떤 때는 꼭 사용해야 기름을 친듯 잘 돌아갑니다.
//( 프로그램이 점점 커지고 기능이 많다보면 뭔가 잘 안돌 때 한번씩 사용합니다 물론 Sleep()과 쌍으로...)
//그런데 이것을 오용하면 이 프로그램에서 처럼 죽습니다.
//----------------------------------------------------------------------------
}
접속 끊을 때는 이렇게....
void __fastcall TForm1::BtnStopRecvClick(TObject *Sender)
{
IdUDPServer1->Active = false;
//실험해보니 아래것 말고 IdUDPServer1->Bindings->Clear(); 이것을 사용해도 잘 되는 군요...
int i=0;
while( i<IdUDPServer1->Bindings->Count )
{
IdUDPServer1->Bindings->Items[i]->Free(); //<--- 핵심은 이 부분......
i++;
}
}
|
감사합니다.