void AsyncSocket_OnReceive(object sender, SessionEventArgs e) { if (IsPushSession() == false) { m_last_receive_time = DateTime.Now.Ticks; TRItem cur_tritem = GetAttachedTRItem(); if (cur_tritem != null) { CommRcvInfo rcv_info = e.GetReceiveInfo(); if (rcv_info != null) { //시퀀스가 동일한지 체크 //if (cur_tritem.nSeq == rcv_info.R_Handle) //{ // 2013/10/22 세션 자동접속을 수동접속으로 변경 // 폴링(91101) 응답시 m_pollingTag 초기화 if (rcv_info.R_TrCode.ToString() == "91101") { RtfGlobal.SessionManager.m_pollingTag = 0; } cur_tritem.SetReceiveTime(e._rcv_time); Debug.WriteLine(string.Format("전송에서 수신까지 ... 소요시간 {0}", cur_tritem.GetLastTimeSpan())); Debug.WriteLine(string.Format(session_name + " [ 소켓에서 데이터 받음 ] TR코드={0}, 데이터={1}...", rcv_info.R_TrCode, rcv_info.R_Data.Substring(0, Math.Min(64, rcv_info.R_Data.Length)))); OnRcvIQData(cur_tritem, rcv_info); //} } } } }
//mapTRItem 맵에 TRItem 추가 public void AddTRItem(TRItem tritem) { lock (lockMapTRItem) { mapTRItem.Add(tritem.nSeq, tritem); } }
private void SendDataToSocket(TRItem tritem) { //tritem 정보를 사용하여 데이터를 전송 //void Data_Send(int PtrCode, int PDest_Way, int PClient_Handle, int Puser_feild, int Pdata_type, int PNext_Len, string PUid, string PInputData); if (bConnected) { this.state = RtfSessionState.ready_request; //핸들값에 nSeq값이 전송된다. if (tritem.inType == 2) { //byte 전송.. m_async_socket.Data_Send(Convert.ToInt32(tritem.strTrCode), // tritem.nSvrNo, // Dest_way (int)tritem.nSeq, // TRItem 시퀀스 tritem.nDataSeq, // 유저데이터 tritem.nDataType, // 0:일반 1:대용량 0, // 넥스트사이즈 "", // 유저아이디( Data_Send 에서 자동으로 채워줌 ) tritem.bytSendData, // 전송데이터 ""); // 종료구분 '0'정상 '1'강제종료 '2'강제종료완료 } else { //string 전송.. m_async_socket.Data_Send(Convert.ToInt32(tritem.strTrCode), // tritem.nSvrNo, // Dest_way (int)tritem.nSeq, // TRItem 시퀀스 tritem.nDataSeq, // 유저데이터 tritem.nDataType, // 0:일반 1:대용량 0, // 넥스트사이즈 "", // 유저아이디( Data_Send 에서 자동으로 채워줌 ) tritem.strSendData, // 전송데이터 ""); // 종료구분 '0'정상 '1'강제종료 '2'강제종료완료 } } }
public void SetSessionReadyState(bool bError) { TRItem tritem = GetAttachedTRItem(); if (tritem != null) { uint nSeq = tritem.nSeq; this.state = RtfSessionState.ready_attach; if (bError) { Debug.WriteLine(string.Format("*** TR 처리에러 nSeq = {0} TRCode = {1} ***", nSeq, tritem.strTrCode)); } else { Debug.WriteLine(string.Format("*** TR 처리완료 nSeq = {0} TRCode = {1} ***", nSeq, tritem.strTrCode)); } DettachTRItem(tritem); //세션이 대기 상태가 되었음을 알림 if (type == RtfSessionType.small || type == RtfSessionType.large) { // if (bConnected) // 세션이 접속되있는 상태일때만 대기상태로 // { ReadyEventArgs args = new ReadyEventArgs(nSeq, type); ReadyEvent(this, args); // } } } }
//화면 종료시에 등록 해제 public void UnregDataAgent(object objToUnreg) { int key = objToUnreg.GetHashCode(); if (mapDataAgent.ContainsKey(key)) { mapDataAgent.Remove(key); Debug.WriteLine("DataAgent 등록해제", category); } //20130107 DataAgent 해제시 세션에서 사용중이면 해당세션 재접속 if (_bShutDownProc == false) { List <RtfSession> dst_listSession = listSessionL; for (int i = 0; i < dst_listSession.Count; i++) { RtfSession session = dst_listSession[i]; TRItem tritem = session.GetAttachedTRItem(); if (tritem != null) { if (tritem.nDataAgentHash == key) { //20130130 조회중 화면 종료시 세션재접속 session.ReconnectToServerByScreenClose(); } } } } }
private TRItem DettachTRItem() { lock (tritemLocker) { TRItem old_tritem = m_tritem; m_tritem = null; return(old_tritem); } }
private void DettachTRItem(TRItem tritem) { lock (tritemLocker) { if (m_tritem == tritem) { m_tritem = null; } } }
public void SetTRItemCancel(TRItem tritem) { //대기중 취소, 세션에 할당된 상태에서 취소가 생길수 있다. TRItemStatus statusBefore = tritem.status; if (statusBefore == TRItemStatus.ready || statusBefore == TRItemStatus.attached) { tritem.status = TRItemStatus.canceled; } }
void SessionManager_OnTimer(object state) { if (_bShutDownProc == false) { //폴링 체크시 디큐를 막는다. PollingTimerStop(); lock (lockDequeue) { // 2013/10/22 세션 자동접속을 수동접속으로 변경 m_pollingTag++; // Debug.WriteLine(string.Format("폴링카운트 : {0}", m_pollingTag.ToString())); // 폴링 데이타가 내려오지 않는것으로 보아 문제가 있는것으로 체크 // 2번 polling 했는데 응답이 없으면 끊어버리고 재연결 메시지 뛰움 if (m_pollingTag > 2) { // 메인프레임으로 알림 // 메인프레임에서 판단(재연결할지, 취소할지) ThreadSafe_OnSessionManagerEvent(this, new SessionManagerEventArgs(SessionManagerEvent.reconnectyn)); return; } //각 세션들의 폴링 상태를 체크한다. for (int i = 0; i < listSessionL.Count; i++) { RtfSession session = listSessionL[i]; //20130130 세션 접속이 끊어진 경우 재접속한다. if (session.bConnected == false) { // session.ReconnectToServerBySessionDisconnected(); } else { //폴링 TR을 전송할지 여부를 체크한다. // if (session.CheckRequestPolling() == true) // { // 2013/12/30 세션이 할당 가능한지 체크를 해주자..... // 대용량 data 연속 조회시 유효성 확보 91101 침범가능 // 연속조회 중간에 서버에 서비스 종료 TR을 전송 문제 발생 (SendToServerServiceExitTR) if (session.IsSessionReady()) { byte[] buffData = null; TRItem tritem_polling = new TRItem(1, "91101", 0, 1, 0, "", buffData, 0); session.AttachTRItem(tritem_polling); } // } } } } // m_pollingTag++; PollingTimerStart(); //폴링 타이머 재가동 // PollingTimerUpdate(); } }
public void Data_Cancel_ByDataAgent(object objDataAgent) { lock (lockMapTRItem) { //동일한 DataAgent일 경우 전부 취소 Dictionary <uint, TRItem> .Enumerator enumerator = mapTRItem.GetEnumerator(); while (enumerator.MoveNext()) { TRItem tritem = enumerator.Current.Value; //동일한 DataAgent일때만 가능하다 if (tritem.nDataAgentHash == objDataAgent.GetHashCode()) { SetTRItemCancel(tritem); } } } }
public void RequestNextDataManual(object objDataAgent) { List <RtfSession> dst_listSession = listSessionL; //현재 사용가능한 세션이 있는지 검색 for (int i = 0; i < dst_listSession.Count; i++) { RtfSession session = dst_listSession[i]; TRItem tritem = session.GetAttachedTRItem(); if (tritem != null) { if (tritem.nDataAgentHash == objDataAgent.GetHashCode()) { session.SendToServerNextData(); } } } }
void AsyncSocket_OnSend(object sender, SessionEventArgs e) { //20121018 : 서버전송 시간 기록 if (IsPushSession() == false) { TRItem cur_tritem = GetAttachedTRItem(); if (cur_tritem != null) { int LogCount = cur_tritem.AddSendTime(DateTime.Now); //2개 이상이면 이전 수신부터 현재 요청까지의 딜레이를 출력 if (LogCount > 1) { Debug.WriteLine(string.Format("수신에서 넥스트 요청까지 지연시간 {0}", cur_tritem.GetLastDelayTimeSpan())); } Debug.WriteLine(string.Format(session_name + " [ OnSend TR코드={0}, {1} bytes! 소켓에서 서버로 데이터 전송 완료... ]", cur_tritem.strTrCode, e.Length)); } } //Debug.WriteLine(string.Format(sock_name + " [ OnSend TR코드={0}, {1} bytes! 소켓에서 서버로 데이터 전송 완료... ]", nSendingTrCode, e.BytesTransferred)); }
//20130725 [4] 대상 DataAgent를 처리중인 세션을 찾는다. public void RequestNextDataManualEx(int SvrNo, object objDataAgent, byte[] ByteSndData) { List <RtfSession> dst_listSession = listSessionL; //현재 사용가능한 세션이 있는지 검색 for (int i = 0; i < dst_listSession.Count; i++) { RtfSession session = dst_listSession[i]; TRItem tritem = session.GetAttachedTRItem(); if (tritem != null) { //세션을 찾음 if (tritem.nDataAgentHash == objDataAgent.GetHashCode()) { session.SendToServerNextDataEx(SvrNo, ByteSndData); } } } }
//Data_Request("3200", 0, 1, 1, str_total); public uint Data_Request(short inType, string strTrCode, int nSvrNo, int nDataSeq, int nDataType, string strSendData, byte[] bytSendData, object objDataAgent) { // DataAgent 등록 ( 화면 종료시에 DataAgent의 유효성을 체크하는데 사용함 ) // 대기중 또는 처리중인 TRItem을 소유하고 있는 DataAgent가 무효한 경우 자동 취소 처리된다. RegDataAgent(objDataAgent); // 화면 또는 RTFDataAgent 에서 데이터요청이 들어온경우 처리 // 일반데이터는 일반 큐에 추가 // 대용량데이터는 대용량 큐에 추가 bool bLarge = true; /* * bool bLarge = false; * if (nDataType == 1) //0:일반 1:대용량 * { * bLarge = true; * } */ //<TRItem> 생성 시작 //TRItem 생성 후 전역으로 관리되는 맵에 추가 < 키:시퀀스, 밸류:TRItem > TRItem tqd = new TRItem(inType, strTrCode, nSvrNo, nDataSeq, nDataType, strSendData, bytSendData, objDataAgent.GetHashCode()); AddTRItem(tqd); //<TRItem> 생성 종료 //대기큐에 추가 시작 Queue <TRItem> dst_queue = null; dst_queue = (bLarge) ? readyQueueL : readyQueueS; dst_queue.Enqueue(tqd); string log = string.Format("{0} 대기큐에 추가. 대기큐 사이즈={1}, TRCode={2}", bLarge ? "Large" : "Small", dst_queue.Count, tqd.strTrCode); Debug.WriteLine(log); //대기큐에 추가 종료 //대기큐에서 유효한 TRItem을 세션에 할당 DequeueReadyQueue(bLarge); return(tqd.nSeq); }
public void AttachTRItem(TRItem tritem) { lock (tritemLocker) { /* * if (this._tritem != null) * { * Debug.WriteLine("tritem!=null 구조적 오류 발생!!"); * return; * } */ this.m_tritem = tritem; tritem.status = TRItemStatus.attached; string log = string.Format("({0}) 세션 {1} 에 TRITEM 할당됨 seq={2}, tr_code={3}, send_data=\"{4}\"", type, id, tritem.nSeq, tritem.strTrCode, tritem.strSendData); Debug.WriteLine(log); //소켓으로 데이터 전송요청 SendDataToSocket(tritem); } }
public void RequestExitDataManual(object objDataAgent) { List <RtfSession> dst_listSession = listSessionL; //현재 사용가능한 세션이 있는지 검색 for (int i = 0; i < dst_listSession.Count; i++) { RtfSession session = dst_listSession[i]; TRItem tritem = session.GetAttachedTRItem(); if (tritem != null) { if (tritem.nDataAgentHash == objDataAgent.GetHashCode()) { //수신 대기인 상태 if (session.state == RtfSessionState.recieved) { session.SendToServerServiceExitTR(); } } } } }
//대기큐에서 TRItem을 하나씩 얻어와서 처리한다. public void DequeueReadyQueue(bool bLarge) { //20130130 셧다운 상태면 더이상 처리하지 않는다. if (_bShutDownProc) { return; } //쓰레드 사용시 DequeueReadyQueue 블럭이 동시에 실행되므로 주의.. //work_session에 이미 TRItem 할당중인 세션이 다시 할당되는 문제 발생.. //크리티컬 섹션으로 블럭킹해서 처리. lock (lockDequeue) { Queue <TRItem> dst_queue = (bLarge) ? readyQueueL : readyQueueS; List <RtfSession> dst_listSession = (bLarge) ? listSessionL : listSessionS; //대기큐가 비어있다면 종료 if (dst_queue.Count < 1) { return; } //현재 사용가능한 세션이 있는지 검색 RtfSession work_session = null; for (int i = 0; i < dst_listSession.Count; i++) { RtfSession session = dst_listSession[i]; //현재 세션이 사용 가능한 상태면 if (session.IsSessionReady()) { //스레드 오류 방지 : 가능상태가 되자마자 불가능 상태로 만들어 버리는 방법( 크리티컬세션 미사용시 오류 최소화 ) work_session = session; break; } //20130130 세션이 접속이 끊어진 상태면 재접속 <자동재접속 사용안함> /* * if (_bShutDownProc == false) * { * if (session.bConnected == false) * { * session.ReconnectToServerBySessionDisconnected(); * } * } */ } //사용가능한 세션이 없으면 종료 if (work_session == null) { return; } //사용가능한 세션이 있다면 ... //큐에서 tritem을 dequeue TRItem tritem_attach = null; while (dst_queue.Count > 0 && tritem_attach == null) { //일단 맨앞에꺼 하나를 꺼내온다. TRItem tritem = dst_queue.Dequeue(); string log = string.Format("***** {0} 대기큐에서 삭제.. 대기큐 사이즈={1} TRItem nSeq={2} 상태={3}", bLarge ? "Large" : "Small", dst_queue.Count, tritem.nSeq, tritem.status); Debug.WriteLine(log); //TRItem의 대상 DataAgent의 유효성을 체크 if (IsValidDataAgent(tritem.nDataAgentHash)) { //현재 대기 상태인 TR아이템만 세션에 할당한다. if (tritem.status == TRItemStatus.ready) { tritem_attach = tritem; break; } } //세션 할당에 실패한 경우 TRItem을 관리 맵에서 삭제 RemoveTRItem(tritem.nSeq); } //세션에 tritem을 등록 if (tritem_attach != null) { work_session.AttachTRItem(tritem_attach); } } }
//20121018 TR데이터 수신처리 public void OnRcvIQData(TRItem cur_tritem, CommRcvInfo rcv_info) { if (cur_tritem == null) { return; } //수신 정보를 저장함 this.last_rcv_info = rcv_info; //수신데이터 헤더부분 파싱 uint nSvrRcvSeq = (uint)rcv_info.R_Handle; uint nSeq = cur_tritem.nSeq; bool bLargeData = (type == RtfSessionType.large) ? true : false; bool bHasNext = (rcv_info.R_NextSize > 0) ? true : false; bool bFinished = true; bool bDataParsing = false; //this.InvokeRequired //세션에서 데이터를 전송하고 세션이 데이터를 받는다고 가정 //서버에서 받는 값은 nSvrRcvSeq //서버에서 받은 시퀀스와 현재 세션의 시퀀스가 다르면 오류 //if ( nSeq != nSvrRcvSeq ) //{ // bFinished = true; //} //DataAgent의 유효성 체크 //bool bValidDataAgent = RtfGlobal.ICMManager.IsValidDataAgent(tritem.nDataAgentHash); object dstDataAgent; bool bValidDataAgent = RtfGlobal.SessionManager.GetValidDataAgent(cur_tritem.nDataAgentHash, out dstDataAgent); bool bAutoNextRequest = false; RTFDataAgent rtfDataAgent = dstDataAgent as RTFDataAgent; if (rtfDataAgent != null) { bAutoNextRequest = rtfDataAgent.bAutoNextRequest; } //수동으로 세션종료를 제어할경우 bool bManualFinish = false; if (rtfDataAgent != null) { bManualFinish = rtfDataAgent.bManualFinish; } //도중에 취소 요청이 들어온경우... bool bCanceled = (cur_tritem.status == TRItemStatus.canceled) ? true : false; //서버에서 응답을 받은 상태 this.state = RtfSessionState.recieved; ////////////////////////////////////////////////////////////////////////// //20120907 취소완료를 받은 경우 bool bCancelCompleted = false; if (rcv_info.R_KillGbn == "2") { rcv_info.R_UserFeild = -1;//마지막데이터 bCancelCompleted = true; bDataParsing = true; bFinished = true; } ////////////////////////////////////////////////////////////////////////// else { //DataAgent 무효하거나 취소된 경우 데이터 파싱 스킵 if (bValidDataAgent == false || bCanceled == true) { if (bCanceled == true) { string strLog = string.Format(">>>>>>>>>>>> TRItem nSeq{0} canceled!", cur_tritem.nSeq); Debug.WriteLine(strLog); } //대용량 데이터일 경우 서버에 서비스 종료 TR을 전송한다 if (bLargeData) { //단, 서버에서 마지막 데이터를 보낸것이면 종료 TR을 전송하지 않는다. //즉 넥스트 데이터가 있는 경우 중지 TR을 전송 if (bHasNext == true) { //서버에 서비스 종료 TR을 전송한다 SendToServerServiceExitTR(rcv_info); //종료된 것이 아님. bFinished = false; } } bDataParsing = false; } //DataAgent가 유효하고 tritem이 취소 상태가 아닐경우 else { //대용량 데이터일 경우 넥스트 데이터가 있다면 넥스트 조회 if (bLargeData) { if (bHasNext) { //20120907 자동넥스트 요청 변경 //대용량데이터 자동 넥스트 요청 //SendToServerNextData(); if (bAutoNextRequest) { //20121212 20121018 속도 테스트 < 스킵처리 > SendToServerNextData(rcv_info);//cur_tritem.inType, //socket.Data_Send(rcv.R_TrCode, rcv.R_DestWay, rcv.R_Handle, rcv.R_UserFeild + 1, rcv.R_Datatype, 0, rcv.R_UserID, rcv.R_NextStr, ""); } //종료된 것이 아님. bFinished = false; } } //데이터를 파싱한다. bDataParsing = true; //20130725 [1] 수동종료일 경우 종료플래그를 FALSE로 셋팅... 세션이 대기상태로 전환되지 않는다. if (bManualFinish)//51108 파일 관리 화면에서만 현재 사용함.. { switch (rcv_info.R_Client_Rtn1) { case 10004: //파일 전송TR에서 파일의 마지막 인 경우 소켓 대기 상태로 변환.. bFinished = true; break; default: //파일 전송TR에서 파일의 마지막 아닌 경우 소켓 대기 상태로 동일한 소켓으로 전송.. bFinished = false; break; } } } } //데이터파싱할 경우 and 대상 DataAgent가 유효할경우 if (bDataParsing == true) { int r_user_field = rcv_info.R_UserFeild; //취소완료 수신 if (bCancelCompleted) { //Data_Reciver.R_LoopDataList.Clear(); } //정상데이터 수신 else { //첫번째 데이터이면 수신리스트 삭제 if (rcv_info.R_UserFeild == 1) { //Data_Reciver.R_LoopDataList.Clear(); } //넥스트가 없으면 마지막데이터 if (rcv_info.R_NextSize == 0) { r_user_field = -1; } } //종료시 전체 시간 출력 if (bFinished) { Debug.WriteLine(string.Format("### 전체 전송에서 수신까지 ... 소요시간 {0}", cur_tritem.GetTotalTimeSpan())); } //해당 화면으로 데이터 전송 if (rtfDataAgent != null) { int pnt = 0; string SendData = rcv_info.R_TrCode.ToString() + SPChar + rcv_info.R_Datatype.ToString() + SPChar + r_user_field.ToString() + SPChar + rcv_info.R_MSG + SPChar + '0' + SPChar; // trcode, pnt, rec_data( trcode | datatype | dataseq | msgcd | 0 ) DataEventArgs args = new DataEventArgs(rcv_info.R_TrCode, (int)pnt, SendData, rcv_info); //쓰레드 세이프 방식 if (RtfGlobal.SessionManager.IsShutDown == false) { rtfDataAgent.ThreadSafe_DataRecvEvent(this, args); } } } //데이터 수신이 완료되면 사용가능 상태로 if (bFinished) { SetSessionReadyState(false); } }