Q&A

  • 도와주십시요.. indy사용한 서버가 매일 다운됩니다.
인디버젼은 indy9.0.18입니다.
delphi 7입니다.


-- excute,부분입니다.
procedure TMainForm.IdTCPServerExecute(AThread: TIdPeerThread);
var
    Header      : TPacketHeader;
begin
     try
        if (AThread <> nil) and (AThread.Connection.Connected) then
        begin
            AThread.Connection.ReadBuffer(Header, HEADER_SIZE );
            if( not SocketProc.ProcessData( AThread, Header.Code, Header.Size ) ) then begin
                AThread.Connection.Disconnect;
                //AThread.Stop;
            end;
        end;
        Sleep(0);
     except
        on E: Exception do
        begin
            if not ( E is EIdConnClosedGracefully )
                and not ( E is EIdNotConnected ) and not (E is EIdSilentException) then
            begin
                if (AThread <> nil) and AThread.Connection.Connected then
                begin
                    AThread.Connection.Disconnect;
                end;
            end;
        end;
     end;
end;


- 서버단에서 클라언트쪽에 데이타를 줄때 다음과같이 보내줍니다.        
        AThread.Connection.OpenWriteBuffer;
        try
            AThread.Connection.WriteBuffer( pHeader^, HEADER_SIZE );
            if ( Size > 0 ) then begin
                AThread.Connection.WriteBuffer( pSendPacked^, Size );
            end;

            //데이타 리스트가 있는경우에는 해당 리스트 데이타를 Write한다.
            //여기스트림부분은 현접속회원리스트(전체) 라든지 아니면 메모리스트 등을 넘깁니다..
            if ( AStream <> nil ) then begin
                if ( DataListSize > 0 ) then begin
                    AThread.Connection.WriteStream( AStream, True, False, DataListSize );  <=== 이부분이 상당히 의심스러움.. (혹시 이부분은 데이타양이 많아지면 문제가 되나요?)
                end;
            end;
            AThread.Connection.CloseWriteBuffer;
        except
            on E:Exception do
            begin
                try
                    AThread.Connection.CancelWriteBuffer;
                except                    
                end;
         end;
        end;


받을시 클라이언트
        -- 보통은 이렇게 받고
        IdTCPClient.ReadBuffer( ReceivePacked, Size );
        -- 스트림이 넘어올시에는 다음과같이 받습니다.
        TmpMemStream := TMemoryStream.Create;
        try
            try
                if ( Size > 0 ) then
                begin
                    IdTCPClient.ReadStream( TmpMemStream, Size, False );

                    TmpMemStream.Position := 0;

                    for ii := 0 to (Size div ListSize) - 1 do
                    begin
                        //new(pTmpListPacked);
                        GetMem( pTmpListPacked, ListSize );
                        TmpMemStream.ReadBuffer( pTmpListPacked^, ListSize );
                        DataList.add( pTmpListPacked );
                    end;
                    Result  := DataList;
                end;
            except
                on E: Exception do
                begin
                    SendJBLoggerException('ReceiveStreamFromServer Error ', E, 'PSS');
                end;
            end;
        finally
            TmpMemStream.Free;
        end;


-- 회원리스트컨트롤은 하나의 criticalsection을 사용합니다.

-- 회원리스트는 클라이언트쪽은 하나의 room리스트를 만들어서 그안에 넣고 뺄때 criticalsection을 사용하구요.

-- 브로드캐스팅(모든사용자에게 어떤값들을 줄때)시에는 criticalsection을 사용하지않고 그냥 하나의room리스트를 for문돌려서 send하구요... (이부분에서 가끔 엄청난 (한 5개~10개정도 에러가납니다. 인볼케이션에러..) 헐..)  ,   어디보니 broadcasting할때는 lock을 해주는게 안정하다고 해서 room리스트에 걸고있는 criticalsection으로 걸어봤는데 그다지 상태가 좋지는 않았습니다.

-- 디비풀쪽은 일반적으로 생각하는 풀링을 사용하면서 항상 mssql의 프로시져를 건드립니다.
   여기서 한가지 의심스러운것은 프로스져들을 보면 update문과 insert 문이 있는데 autocommit을 true로 사용하여 하나의 프로시져안에서 insert도 하고 update하고 마지막에 select도 합니다. 건드리는테이블은 그냥 이것저것 건드리구요..  어디에서 보니 insert, update는 트렌젝션을 항상 먹여서 하나씩 하는게 좋다고 하는데.. 그렇다면 현재 사용하는 프로시져들을 하나씩 잘게 썰어서 insert, update, delete 를 따로만들고 그때마다 트랜잭션을 먹이고, select를 따로 만들어 여러개로 만들어 정확히 하나하나테이블마다 트랜잭션을 적용해야하는지요...  디비컴포넌트는 zeosdbo-6.1.5-stable 를 사용합니다.
    1. 일반 update쪽할때.. (트랜젝션 적용)

    Connection.SetAutoCommit(False);
    Connection.SetTransactionIsolation(tiReadCommitted);
    ....PrepareStatement 날리고
    Connection.commit;

    2. update, insert 등도 하면서 마지막에 select할시 (트랜잭션 적용안함)
    Connection.SetAutoCommit(True);
    ....PrepareStatement 날리고
    Result := Statement.ExecuteQueryPrepared;   해서 ResultSet데이타를 받습니다.

-- 서버단의 에러현상
  -> 1. 접속은 되는데 (로그인) , disconnect쪽이 잘안되는부분 (,로그아웃),  로그인했다가 로그아웃하고 다시 로그인하면 이전 로그인한 Athread가 남아있습니다 ( 아니면 제가 만들 room리스트에서 제대로 삭제가 안된것일수도.).
  -> 2. 로그인한 회원들은 사용되는데 로그아웃했다가 다시 로그인할려하면 서버에 접속이 안되는 현상..


꼭좀 도움 부탁드리겠습니다. 델파이 쉽게만 생각했는데 너무 어렵네요...
단어하나라도 좋으니 조언부탁드립니다...
3  COMMENTS
  • Profile
    이영화 2006.03.28 20:11
    우선 소켓 해제 하는 부분에 WHILE TRUE 하나 넣어보세요.

    소켓이라는게 끊어라 그런다고 무조건 넵 그러진 않을 수도 있습니다.
    (혹시라도 TCP Transition Diagram 같은거 대충 보셨다면... 함 진지하게 봐보세요.
      FIN_WAIT 같은거 ....)


    (단순히.. 예를 든것뿐입니다)

    WHILE TRUE DO
    BEGIN
       IF NOT Socket.Connected THEN    // 정말로 끊김.
           BREAK;

       INC(Loop_Count);  

       IF Loop_Count > 50 THEN // 0.1초 * 50 = 5초 맞죠?   기다릴 만큼 기다렸으니까 나갑시당.
           BREAK;

       SLEEP(100);
    END;




    서버가 다운되는 현상은 조금 더 상세히 기술하셔야 할 듯...

    그리고, 소켓 프로그램이든 머든,,,
    버퍼 사이즈 보다 큰 데이타를 버퍼에 밀어넣을 수 있는 부분이 있으면 안되겠죠..
    Size > 0 테스트만 하시지 마시고..
    Size <= Buffer_Size  같은 것도 병행하시면 좀 코드가 튼튼해 보이겠네요.


    디버깅은 게임입니다.
    재밌다고 생각하시고 꼭 싸워서 이겨보세요.


  • Profile
    임상돈 2006.03.29 03:06
    서버에서 writebuffer 쪽에서 에러나서   cancelwritebuffer 도 에러가나는현상이 있습니다.
    10053 에러나 10054에러입니다.
    한데 10053와 10054에러는 네트웍이 갑자기끊어지는 현상때문이라고 기술되어있지만
    지금 제쪽에서 나는 에러는 뭔가가 부족해서 나는거같습니다.

    보통 유저들이 동시에 접속을 시도했을경우(최소 5명이상으로 추측) 많이 나타나는 현상입니다.
    가끔 인볼케이션에러도 나오는것 같기도 했습니다.

    한데 문제는 어느시점에서 갑자기  writebuffer 나  send(로직-브로드케스팅하는부분)  부분쪽에서
    엄청난 인볼케이션 에러들이 등장하게 됩니다. 그러면서 서버는 접속해있는사람들은 접속은 되어있지만
    뭔가 제대로 동작을 하지 않게 되며 메시지를 보내면 보내지지않습니다. 가끔 깨진메시지가
    도착하곤합니다.
    하여 로그아웃했다가 다시 로그인할려하면 서버에서는 알수없는 데이타들을 보내고..
    또는 서버에 접속자체가 안되는 현상이 있습니다.
    죽을때 서버가 CPU는 안먹지만 가끔은 인터페이스가 얼어있있습니다.
  • Profile
    이영화 2006.03.29 18:41
    "인볼케이션에러" 이 용어 생전 첨봅니다(ㅠㅠ)
    원래 용어로 좀 알켜 주세요.
    그리고, 10053, 10054는 구체적으로 서버, 클라이언트 어느쪽에서 발생하는지도
    잘 모르겠네요.

    질문하시는 분위기로 보아서는 금방 도사되시겠어요.
    여러가지 자료를 찾아보시고 그래도 안될 때는
    여기처럼 활발한 커뮤니티에 자문구하는게 젤이죠.
    실력 금방 늘거에요.

    만약 AV가 발생하는게 맞다면
    이 넘은 사고발생지점에서 얼마나 멀리 떨어져서 비명소리가 나는지
    거의 알아내기 힘든 코딩상의 버그니까
    심호흡하시고, 소스 찬찬히 들여다 보셔야 할겁니다.

    지난번 질문도 그렇고, 지금도 그렇습니다만.

    조금 더 문제상황에 대해 Descriptive하게 부탁드립니다.

    (최소한 5개이상의 질문 혹은 문제점이 동시에 표현되고 있는 듯합니다.)

    하나씩 잡는게 젤이죠.


    아마 지금 겪고 계신 문제는 통신 초보자(저도 포함입니다.)에게 많은 도움이 될 겁니다.
    어설픈 강좌보다는 이렇게 실제상황이 아주 도움이 되는 법이죠.
    게임이 끝나시면 살짝 회고록(!) 하나 올려보셔도 될 듯.

    계속 홧팅하시고.
    조만간 게임에서 이기실 것 같네요.
    미리 추카드립니다.
    (질문에 구체적인 표현이 많을수록 버그 실체가 거의 드러난 거거든요. 보이면 잡을 수 있짢아요..)

    아래 내용은 말 그대로 레퍼런스(무슨 책 부록인 듯..) 긁은 거니까
    보이는 만큼만 참고해 보세요.
    (아마 보셨을 지도 모르겠지만 여기가 게시판 이니까 혹시나 못보신 분들을 위해서요...)

    =========================

    Berkeley description: A connection abort was caused internal to your host machine. The software caused a connection abort because there is no space on the socket's queue and the socket cannot receive further connections.

    WinSock description: Partly the same as Berkeley. The error can occur when the local network system aborts a connection. This would occur if WinSock aborts an established connection after data retransmission fails (receiver never acknowledges data sent on a datastream socket).

    TCP/IP scenario: A connection will timeout if the local system doesn't receive an (ACK)nowledgement for data sent. It would also timeout if a (FIN)ish TCP packet is not ACK'd (and even if the FIN is ACK'd, it will eventually timeout if a FIN is not returned).

    User suggestions: There are a number of things to check, that might help to identify why the failure occurred. Basically, you want to identify where the problem occurred.

    Ping the remote host you were connected to. If it doesn't respond, it might be off-line or there may be a network problem along the way. If it does respond, then this problem might have been a transient one (so you can reconnect now), or the server application you were connected to might have terminated (so you might not be able to connect again).
    Ping a local host to verify that your local network is still functioning (if on a serial connection, see next step)
    Ping your local router address. If you're on a serial connection, your local router is the IP address of the host you initially logged onto with SLIP or PPP.
    Ping a host on the same subnet as the host you were connected to (if you know one). This will verify that the destination network is functioning.
    Try a "traceroute" to the host you were connected to. This won't reveal too much unless you know the router addresses at the remote end, but it might help to identify if the problem is somewhere along the way.

    ---------------------------


    Berkeley description: A connection was forcibly closed by a peer. This normally results from a loss of the connection on the remote socket due to a timeout or a reboot.

    WinSock description: Same as Berkeley. On a datastream socket, the connection was reset. This reset could be generated locally by the network system when it detects a connection failure, or it might be received from the remote host (in TCP terms, the remote host sent a RST packet). This error is also possible on a datagram socket; for instance, this error could result if your application sends a UDP datagram to a host, which rejects it by responding with an ICMP Port Unreachable.

    User suggestions: Some network systems have commands to report statistics. In this case, it might be possible to check the count of TCP RST packets received, or ICMP Port Unreachable packets. See other suggestions under WSAECONNABORTED.


    ==============================================


    • 박성준
    • 2006.03.28 10:24
    • 5 COMMENTS
    • /
    • 0 LIKES
    • 이영화
      2006.03.29 18:50
      Genetic Algorithm이라면 영어실력 혹은 능력과는 전혀 무관합니당.(^^) 우선 다른 기초자료부터 조금(...
    • 박성준
      2006.03.30 19:18
      우선 답변 주셔서 감사드립니다... 전 대학원 생입니다. 교수님께서 공부할겸 해석해보라고 하셔서 계...
    • KDDG_Han
      2006.03.29 19:54
      잠깐 열어봤는데, 도와줄 수 있는 분이 아마 거의 없지 않을까 싶네요. 신경망, 유전자 알고리즘, 미니맥...
    • 박성준
      2006.03.30 19:20
      교수님께서 논문의 내용중 한쪽만 해석해보라고 해서... 몇일 못했더니 해석이 오래걸리냐고... 전 제...
    • 이영화
      2006.03.30 22:47
      OR쪽 전공이신가 보군요. 읽을만한 논문이란게 있고 레퍼런스에 제목만 올려 놓아야할 논문이 있다면.. ...
    • 석주현
      2006.03.29 00:55
      코드를 보니 왠지 DVR 냄새가 많이 나는군요. DVR 코드 특성상 Frame Buffer의 포인터를 넘기는 경우가 ...
    • 탁선호
      2006.03.29 01:55
      예, DVR 보드를 이용한 어플입니다..^^ 그런데 소나기님 FrameBuffer을 읽어서 한점씩 그린다고 하셨는...
    • 박상윤
      2006.03.30 01:43
      일단 들어오는 비트 맵의 구조를 알아야 합니다. 비트 수에 따라 틀리져.. 그리구. RaW파일인지.. 헤더 ...
    • 임상돈
    • 2006.03.28 00:21
    • 3 COMMENTS
    • /
    • 0 LIKES
    • 이영화
      2006.03.28 20:11
      우선 소켓 해제 하는 부분에 WHILE TRUE 하나 넣어보세요. 소켓이라는게 끊어라 그런다고 무조건 넵 그...
    • 임상돈
      2006.03.29 03:06
      서버에서 writebuffer 쪽에서 에러나서   cancelwritebuffer 도 에러가나는현상이 있습니다. 10...
    • 이영화
      2006.03.29 18:41
      "인볼케이션에러" 이 용어 생전 첨봅니다(ㅠㅠ) 원래 용어로 좀 알켜 주세요. 그리고, 10053, 10054는 구...
    • 황당한초보
      2006.09.07 14:20
      해보진 않았지만, usb 인지에 관한 답변이 있어 연결해드립니다.. http://www.delmadang.com/cwb-bin/Cr...
    • 김범진
    • 2006.03.27 12:09
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2006.03.27 22:20
      안녕하세요. 최용일입니다. 도움말의 "Real types"부분을 보시면 Single은 7~8, Double은 15~16으로 유...
    • 111
    • 2006.03.25 21:13
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 정경철
    • 2006.03.25 03:20
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 하나로
      2006.03.26 11:36
      해당 연주하고자 하는 파일이 Error.Wav 일경우 <!--CodeS--> PlaySound('c:\SAMPLE\Error....
    • 김종곤
    • 2006.03.24 20:31
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2006.03.24 22:33
      안녕하세요. 최용일입니다. 음... 뭔가 다른 작업과 연관되어서 에러가 발생하는것 같은데요... Inva...
    • 최용일
      2006.03.24 22:31
      안녕하세요. 최용일입니다. 쓰레드하나 만들어서 그곳에서 클라이언트소켓에서 읽는 작업을 하시면 됩니...
    • 희아빠
      2006.04.07 22:03
      감사합니다..... 답변을 보고도 이제야 감사의 글을 드리내요 ^^ 관심에 감사드립니다,
    • 표경만
      2006.03.31 21:53
      이 문장은 FULL JOIN 을 사용한 방법입니다. 참고하세요 select isnull(a.일자, b.일자) as 일자, 매출...
    • 이상대
      2006.03.24 18:06
      select 일자,sum(매출액),sum(수금액),sum(매입액),sum(결제액)  from ( select 일자,매출액,...
    • 최용일
      2006.03.24 22:47
      안녕하세요. 최용일입니다. 기본적인 구조는 TDlgTemplate구조체와 TDlgItemTemplate구조체의 배열로 되...
    • 강경수
      2006.03.29 01:11
      제가 사용하는 방법에서 질문한 내용으로 변경해 적어봅니다. 도움이 되면 좋겠네요... procedure TFor...
    • 김홍철
      2006.03.24 03:32
      전에 프로그램 하나 만들면서 짯던 부분이 있는데, 같은 기능을 할거같네요.... 참조하세여.... <!...
    • 최용일
      2006.03.24 22:30
      안녕하세요. 최용일입니다. FindFirst/FindNext/FindClose함수를 이용해서 ShellTreeView에서 선택된 폴...
    • 하태희
      2006.03.25 02:27
      20개의 개체를 만들면서 Query1.FieldByName('name').AsString 을 개체명에 부여하는 것으로 하여야 할것...
    • 나그네
      2006.03.24 23:08
      m_name 이라는 Label 컴포넌트의 캡션을 바꾸려고 하는건가요? m_name.Caption := Query1.FieldByName('...
    • 송유철
      2006.03.23 23:42
      m_name 자체는 라벨 이름일텐데 넣는거 자체가 좀 말이 안되는거구요 어떤식을 원하는건지요?? 라벨 ...
    • 이승근
      2006.03.24 16:30
      질문이 좀 모자란듯 싶네요...^^;; 그러니깐 일종의 명세서 폼에 기입되는 QRLabel이 약 20여개 됩니다......
    • 착한천사
      2006.03.26 02:01
      착한천사 김경록입니다. 음.. 답변을 쓰신것도 조금 이해가 안되는군요.. 제가 보기엔 DB에 저장된 ...
    • 주재환
      2006.03.23 21:51
      먼저 왜 에러가 나는지 파악하셔야 할 것 같은데요... 데이터 문제 인 것 같은데...
    • 최용일
      2006.03.23 02:59
      안녕하세요. 최용일입니다 그 키는 문자열값이 아니라 문자열배열값이구요. 레지스트리 편집기로 열어보...
    • 남상훈
    • 2006.03.22 19:20
    • 6 COMMENTS
    • /
    • 0 LIKES
    • 박면구
      2006.03.23 00:04
      오라클, mysql, msSql 등등 의 경우 파라메터를 이용하여 사용하는 것이 프로그램이 도움이 됩니다. d...
    • 방극선
      2006.03.22 21:01
      . 델파이는 파스칼 이라 string 을 구별하는데 ' ' 를 사용합니다. . 즉 'sss ddd  ffff'...
    • 송유철
      2006.03.22 20:54
      select * from MASTERM   where pid='001' 이걸 쓰신다면 dm.master_q.sql.Add('sele...
    • 남상훈
      2006.03.22 22:28
      정말 감사합니다. 머리에 쏙 들어오는 설명이었습니다. 한가지만 더 물어보겠습니다. select * fro...
    • 박지용
      2006.03.24 07:35
      ========================================== 질문의 핵심은 '' 묶을 때 좀 더낳은 방법을 찾는 것 같...
    • 송유철
      2006.03.23 01:16
      다른 분들 말들 처럼 파라미터값을 사용하는것도 한 방법인데요 일단은 적어 놓으신걸 기준으로 설명 ...