|
C++ Crl 프로젝트로 만들고 있습니다.
일본의 어떤 회사에서 CAD도면 관리하는 프로그램하고 API를 만든게 있어서 저희가 그걸 쓰고있는데요.
dll파일을 import해서 필요한 인터페이스를 인스턴스화 했습니다.
그리고 Login이라는 함수를 이용하면 이 API가 지정해준 서버 주소로가서 CAD도면 관리 프로그램이 있는에 로그인 후 결과를 알려줍니다.
Ipc3dxCorePtr m_pc3dCore; <- 인터페이스
m_pc3dCore = NULL;
CoInitialize(NULL);
HRESULT hr = m_pc3dCore.CreateInstance(__uuidof(pc3dxCore)); <- 인스턴스생성
BOOL rc = m_pc3dCore->Login(m_CdmUser, m_CdmUserPass, m_CdmServer); <- Login함수 호출 여기서 응답없음
처리에 필요한 최소한의 소스만 적어보면 이정도입니다.
보통은 잘 움직입니다. 아이피랑 프로그램 로그인에 필요한 정보 제대로 넣어주면 성공메세지가 돌아오고. 잘못된 정보 입력하거나 하면 실패메세지가 돌아옵니다.
근데 서버 하나만 Login함수 호출에서 걍 영원히 응답이 안옵니다. 디버깅으로 다음줄로 넘어갈 수 가 없어요. 보니까 서버에서 ping은 오던데 아마 서버는 기동중이나 어플리케이션이 기동될 수 없는 상태이거나 뭐 그런것 같습니다.
---여기까지가 발생중인 문제----
여기서 한가지 여쭙고싶은건..try catch걸어도 소용없고. 애초에 소스가 다음줄로 진행이 안되는데 일반적인 방법으론 답이 없을 것 같아서. Login처리를 System::Thread내에서 처리하면서 시간이 지나면 강제로 Thread에서 나오는식으로 해결 하려고 하고있습니다.
여러분은 이 방법에 대해 어떻게 생각하나요? 쉽게 갈 수 있는걸 제가 어렵게 하려고 하는건지. 아니면 다른분들 생가에도 이게 맞는건지 여쭙고싶습니다(쓰레드는 오늘 처음써봐서 미숙합니다)
그리고 오늘 하루종일 쓰레드로 처리하도록 하면서 거의 다 완성 되었는데 마지막에 도저히 풀리지않는 문제가 있어서 그것에대해서 여쭙고싶습니다.
--- 여기부터 쓰레드 구현후에도 발생하는 문제---
간단하게 설명하고 소스를 좀 적겠습니다. 일단 Login하는 대상이 하나가 아닙니다. 설정파일에따라 여러 서버에 접속을 시도합니다. 그래서 설정파일에서 대상이 몇개인지 확인 후 루프 돌려서 루프 안에서 Login처리를 계속합니다. 인터페이스의 인스턴스화는 어떻게 머리를 잘 굴려서 겨우겨우 루프밖에서 한번만 하도록 했습니다. 잠시 소스 적고 가겠습니다.
ref class Work -----쓰레드에서 불러들이기 위해 만든 클래스
{
public:
static void DoWork()
{}
int Data;
int getresult;
String^ ip;
String^ name;
String^ pass;
marshal_context context;
Ipc3dxCorePtr* m_pc3dCore; ---- 외부에서 인스턴스화 한 인터페이스를 포인터로 받아옴, 포인터 아니면 여기서 선언안됨.
void DoMoreWork()
{
Ipc3dxCorePtr core = *m_pc3dCore; ----- 포인터로 받아온거 여기서 넣음.
BOOL rc = core->Login(context.marshal_as<const TCHAR*>(name),
context.marshal_as<const TCHAR*>(pass),
context.marshal_as<const TCHAR*>(ip));
if (rc == TRUE) {
result = 1;
}
else if(rc == FALSE) {
result = 2;
}
core->Logout();
}
};
bool LoginCdm::Login() ----- 기본 처리 함수
{
CString AddInfo;
CoInitialize(NULL);
m_pc3dCore = new Ipc3dxCorePtr(); /// .h파일에서 Ipc3dxCorePtr* m_pc3dCore; 해놓은거 new로 생성
HRESULT hr = m_pc3dCore->CreateInstance(__uuidof(pc3dxCore)); /// 인스턴스생성
Work^ w = gcnew Work;
for(int a = 1; a <= resultIni ; a++) /// 설정파일에서 딴 처리대상을 LoginCdm클래스의 변수에 넣어놨습니다.
{
CString num;
w->Data = resultIni;
w->ip = gcnew String( m_CdmServer);
w->name = gcnew String( m_CdmUser);
w->pass = gcnew String( m_CdmUserPass);
w->result = 0;
w->m_pc3dCore = m_pc3dCore;
ThreadStart^ threadDelegate = gcnew ThreadStart( w, &Work::DoMoreWork );
Thread^ newThread = gcnew Thread( threadDelegate );
newThread->Start();
newThread->Join(7000); // 7초동안 응답없으면 쓰레드 걍제로 나옴.
if(w->result == 0)
{
w->getresult = 10;
Console::WriteLine("Timeout");
}
else if(w->result == 2)
{
Console::WriteLine("false");
}
else Console::WriteLine("true");
}
이런식입니다. H_RESULT결과에대한 처리나 그런건 소스가 길어지므로 최대한 지웠습니다.
여기서 문제가 뭐냐면요. 예를들어 처리 대상이 4개라고 할때. 첫번째 서버에 접속 성공했습니다. OK 문제없음.
근데 두번째거에서 타임아웃이 발생했습니다. 그럼 쓰레드에 시간 걸어놨기때문에 처리 중단하고 밖으로 나오고. TimeOut메세지 출력 후에 3번째거 처리합니다. 이 3번째, 4번째가 문제가 되는데요. 3번째 4번째는 정상적으로 움직이고 있는 서버이기때문에 true나 정보를 잘못 입력했을경우 false가 나옵니다. 타임아웃되지않습니다. 문제는 2번째에서 타임아웃이 되버리면. 이 3번째 4번째도 타임아웃이 되버러리는 겁니다..
어디서 타임아웃이 되냐하면, Login메소드를 불러들이는 인스턴스화한 클래스 core의 처리에서 타임아웃합니다.
처음엔 한번 타움아웃하면서 인스턴스가 맛탱이가 가는건가 싶어서 여기서는 소스를 지워놨지만 타임아웃이 한번 발 생 했을시에는 인터페이스에 NULL을 넣어서 core랑 인스턴스화 해놓은것들 다 초기화 해봤는데. 그 뒤에 다시 core.CreateInstance하거나 할때 변함없이 응답이없고 타임아웃합니다. NULL도 넣어봤고 delete도 해봤고 api 설명서 보니까 Flashxx()라는 함수로 메모리 정보를 지울 수 있다길래 그겄도 해봤는데 Flashxx는 애초에 core에 속해있는 메소드라 저거 부른 시점에서 이미 또 멈춰버리고...아무리 인스턴스를 새로 만들어서 해봐도 소용이 없더라구요...결국엔 core안에 있는 메소드를 불러오면 거기서 멈춰버립니다...
한번 타임아웃이 발생하면 그 뒤에 처리하는것들은 다 그래요 ㅠ.ㅠ...
도저히 이유를 모르겠습니다. 짐작가는 부분 없을까요??
---마지막으로
몇년전에 C#으로 비슷하게 서버에서 응답이 안오고 무한로딩하는걸 고첬던 기억이있는데...이직하기 전회사라 자료도 없고 기억도 애매한데...결국 서버에서 IIS설정에서 타임아웃 시간 설정해주면 쓰레드따위 안써도 걍 타임아웃했다고 돌아올 것 같은데 -_-...제가 만질 수 없는 서버라 확인도 못했고...내일 한번 관리자한테 물어볼까 생각도 하고있는데 다른분들은 어떻게 생각하시나요? 애초에 서버에서 응답이 죽을때까지 안오는건 서버에서 타임아웃 설정을 안해놔서 그런걸까요?
질문이 좀 많이 길지만 도움부탁드립니다!
|