Q&A

  • [고수분의 답변 요청] Socket 사용시 Text가 붙어 버리는 현상


도저히 해결 못해서 할 수 없이 도움을 요청합니다.

델파이의 문제 같기도 한데 ...



문제는 이런 겁니다.



보내는 쪽에서는 아래와 같이 For 문을 사용해서 100개의 Text를 보냅니다.



For Count := 1 to 100 do

XSocket.SendText('Message'+IntToStr(Count)+#10#13);



받는 쪽에서는 해당 메시지마다 Ack를 보냅니다.



OnReceive

YSocket.SendText('Ack');



그러면 누가 생각하건 간에 보낸쪽은 100개의 Ack를 받아야합니다.

그러니 현실은 그렇지가 못합니다.



받은쪽에서 조사를 해보니 보내는 메시지가 붙어서 도착을 하였습니다.



즉, Message1, Message2, Message3, Message4, ...이렇게 보내어져야 하는데,



Message1Message2, Message3, Message4Message5Message6Message7, Message8Message9, ... 처럼 Random하게 붙어서 보내어 집니다.



즉, 받는 입장에서는 아무리 빨리 도착을 해도 끊어져서 제대로 처리가 되는데,

보내는 입장에서는 아주 빨리 보내면 위와 같이 따로 끊어서 보낸 것이 대중없이 붙어서 가버립니다. 위처럼 For 문으로 하지않고

XSocket.SendText('Message'+IntToStr(1)+#10#13);

XSocket.SendText('Message'+IntToStr(2)+#10#13);

XSocket.SendText('Message'+IntToStr(3)+#10#13);

...

이렇게 해도 마찬가지입니다.



이제 분명해진건 SendText가 받는 사람의 입장에서 하나의 OnReceive Event를 발생시키지 않는다는 것입니다.



제가 하고 싶은건 하나의 Text를 보낼때 받는 쪽의 입장에서도 정확히 그 Text를 받아 보는 것입니다.

물론 천천히(1초에 한번 정도 SendText를 실행) 보낼때는 SendText가 하나의 단위로 끊어 집니다.



아주 빨리 보내더라도 Text가 붙어 버리지 않게 보내는 방법이 없을까요?



Disk Cache의 경우에는 Flush라는 강제적인 명령이 있는데 Socket 송신 Buffer에 대해서 그런 행동을 하겠끔 하는 메커니즘은 없는가요?



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

참고로

위의 상황에서 Socket은 Blocking Type이 아닙니다. NonBlocking Type이며 저는 NonBlocking Type에서 위와 같은 일을 하고 싶습니다.

Blocking Type은 안정적이지만 좀 비효율적이라 저는 사용치 않습니다.

그리고 위와같은 문제는 Blocking Type으로 해도 똑같이 발생할걸로 생각이 됩니다.





5  COMMENTS
  • Profile
    Hoon Reader 2000.08.12 00:45


    아래 분의 말씀처럼 TCP/IP의 본질적인 문제는 아닙니다.

    그리고 저는 원격으로 가동할 수 있는 컴퓨터가 4대나 됩니다. 그런 작업은 윈도우2000서버의 터미널 서비스(PCAnywhere 써본 사람은 그것과 같다라는 걸 알겁니다)를 통해 가능하죠. 4대 모두 지역적으로나 Routing Hop을 봐도 많이 떨어져 있지죠. 즉 Local 테스트가 아니라는 말입니다.



    제가 다시 델파이의 도움말을 자세히
  • Profile
    corbie` 2000.08.18 03:17
    한때는 이거때문에 고심한적이 있는데



    리턴값이 데이터 Writeing 된만큼 리턴되던데요. 소켓 컴포넌트 소스를 뒤져봐두



    Send <-- 요 Winsock함수를 사용하는데요 이 함수 의 리턴값을 주는거 가떤데요



    이함수 사용법은. msdn 에 잘찾아 보시면. 그런거 가떤데요..



    그리구요 확실히 아래 도움말은 믿지 몬해요 -_-



    "SendText returns 0 if the string was successfully written. It returns a nonzero value if the writing must be posponed. When SendText returns a nonzero value, it must be called again later to write the value over the connection



    Hoon Reader wrote:

    >

    > 아래 분의 말씀처럼 TCP/IP의 본질적인 문제는 아닙니다.

    > 그리고 저는 원격으로 가동할 수 있는 컴퓨터가 4대나 됩니다. 그런 작업은 윈도우2000서버의 터미널 서비스(PCAnywhere 써본 사람은 그것과 같다라는 걸 알겁니다)를 통해 가능하죠. 4대 모두 지역적으로나 Routing Hop을 봐도 많이 떨어져 있지죠. 즉 Local 테스트가 아니라는 말입니다.

    >

    > 제가 다시 델파이의 도움말을 자세히
  • Profile
    타락천사 2000.08.07 19:09
    안녕하세여..타락임다..^^



    하나의 컴에 서버와 클라이언트 띄워놓구 테스트한거져?



    그런 경우는 네트워크에서두 거의 발생 안합니다.. 인터넷에선 발생 안하는걸루 압니다.



    그건 델파이 문제가 아니라, TCP/IP 문제 입니다..



    글구 Blocking Mode 로 하면 발생하지 않습니다.



    왜 그런 문제가 발생하는가 하면여...



    CPU의 처리속도에 비해 I/O Device의 처리속도는 무한대예여..



    적절히 딜레이를 걸어서 비슷하게라두 해줘야져..



    도움이 되길 바랍니다..



    타락천사.....^______________^



    Hoon Reader wrote:

    >

    > 도저히 해결 못해서 할 수 없이 도움을 요청합니다.

    > 델파이의 문제 같기도 한데 ...

    >

    > 문제는 이런 겁니다.

    >

    > 보내는 쪽에서는 아래와 같이 For 문을 사용해서 100개의 Text를 보냅니다.

    >

    > For Count := 1 to 100 do

    > XSocket.SendText('Message'+IntToStr(Count)+#10#13);

    >

    > 받는 쪽에서는 해당 메시지마다 Ack를 보냅니다.

    >

    > OnReceive

    > YSocket.SendText('Ack');

    >

    > 그러면 누가 생각하건 간에 보낸쪽은 100개의 Ack를 받아야합니다.

    > 그러니 현실은 그렇지가 못합니다.

    >

    > 받은쪽에서 조사를 해보니 보내는 메시지가 붙어서 도착을 하였습니다.

    >

    > 즉, Message1, Message2, Message3, Message4, ...이렇게 보내어져야 하는데,

    >

    > Message1Message2, Message3, Message4Message5Message6Message7, Message8Message9, ... 처럼 Random하게 붙어서 보내어 집니다.

    >

    > 즉, 받는 입장에서는 아무리 빨리 도착을 해도 끊어져서 제대로 처리가 되는데,

    > 보내는 입장에서는 아주 빨리 보내면 위와 같이 따로 끊어서 보낸 것이 대중없이 붙어서 가버립니다. 위처럼 For 문으로 하지않고

    > XSocket.SendText('Message'+IntToStr(1)+#10#13);

    > XSocket.SendText('Message'+IntToStr(2)+#10#13);

    > XSocket.SendText('Message'+IntToStr(3)+#10#13);

    > ...

    > 이렇게 해도 마찬가지입니다.

    >

    > 이제 분명해진건 SendText가 받는 사람의 입장에서 하나의 OnReceive Event를 발생시키지 않는다는 것입니다.

    >

    > 제가 하고 싶은건 하나의 Text를 보낼때 받는 쪽의 입장에서도 정확히 그 Text를 받아 보는 것입니다.

    > 물론 천천히(1초에 한번 정도 SendText를 실행) 보낼때는 SendText가 하나의 단위로 끊어 집니다.

    >

    > 아주 빨리 보내더라도 Text가 붙어 버리지 않게 보내는 방법이 없을까요?

    >

    > Disk Cache의 경우에는 Flush라는 강제적인 명령이 있는데 Socket 송신 Buffer에 대해서 그런 행동을 하겠끔 하는 메커니즘은 없는가요?

    >

    > --------------------------------------------------------------------------------

    > 참고로

    > 위의 상황에서 Socket은 Blocking Type이 아닙니다. NonBlocking Type이며 저는 NonBlocking Type에서 위와 같은 일을 하고 싶습니다.

    > Blocking Type은 안정적이지만 좀 비효율적이라 저는 사용치 않습니다.

    > 그리고 위와같은 문제는 Blocking Type으로 해도 똑같이 발생할걸로 생각이 됩니다.

    >

    >

  • Profile
    corbie` 2000.08.18 03:10
    아님니다. TCP/IP의 문제가 아니라. 그기에 대한 성격이겠죠.



    TCP는 UDP같은 데이터 그램이 아닌 스트림 형태라. 조각으로 날라가지가 않습니다..



    그냥 쭈욱 가따 붇는거죠. 블럭킹으로 하드라도 매나 같은 현상이 일어남니다.



    보낼때의 데이터랑. 받을때의 데이터랑 패킷의 크기가 변동되지만.



    다 받게 되었을경우. 데이터 손실없이. 도착한다는 장점이 잇구요 커낵션을 주기때문에



    Accept 가되면. 크 소켓 헨들로. 쓰주기만하믄되니깐. 데이터 전달 경로를 지정하기 쉽



    구요 UDP같은 경우는 데이터 그램이라. 보낼적 사이즈 크기루. 받을때 소켓 이벤트가



    발생이 되구요. 각 데이터 별루 아이피와 포트를 채크해서 분류 시켜 줘야한다는게



    짜증나구요 데이터가 조금오류가 발생하면 아마 도착 이벤트가 발생이 안될껄요.





    > Hoon Reader wrote:

    > >

    > > 도저히 해결 못해서 할 수 없이 도움을 요청합니다.

    > > 델파이의 문제 같기도 한데 ...

    > >

    > > 문제는 이런 겁니다.

    > >

    > > 보내는 쪽에서는 아래와 같이 For 문을 사용해서 100개의 Text를 보냅니다.

    > >

    > > For Count := 1 to 100 do

    > > XSocket.SendText('Message'+IntToStr(Count)+#10#13);

    > >

    > > 받는 쪽에서는 해당 메시지마다 Ack를 보냅니다.

    > >

    > > OnReceive

    > > YSocket.SendText('Ack');

    > >

    > > 그러면 누가 생각하건 간에 보낸쪽은 100개의 Ack를 받아야합니다.

    > > 그러니 현실은 그렇지가 못합니다.

    > >

    > > 받은쪽에서 조사를 해보니 보내는 메시지가 붙어서 도착을 하였습니다.

    > >

    > > 즉, Message1, Message2, Message3, Message4, ...이렇게 보내어져야 하는데,

    > >

    > > Message1Message2, Message3, Message4Message5Message6Message7, Message8Message9, ... 처럼 Random하게 붙어서 보내어 집니다.

    > >

    > > 즉, 받는 입장에서는 아무리 빨리 도착을 해도 끊어져서 제대로 처리가 되는데,

    > > 보내는 입장에서는 아주 빨리 보내면 위와 같이 따로 끊어서 보낸 것이 대중없이 붙어서 가버립니다. 위처럼 For 문으로 하지않고

    > > XSocket.SendText('Message'+IntToStr(1)+#10#13);

    > > XSocket.SendText('Message'+IntToStr(2)+#10#13);

    > > XSocket.SendText('Message'+IntToStr(3)+#10#13);

    > > ...

    > > 이렇게 해도 마찬가지입니다.

    > >

    > > 이제 분명해진건 SendText가 받는 사람의 입장에서 하나의 OnReceive Event를 발생시키지 않는다는 것입니다.

    > >

    > > 제가 하고 싶은건 하나의 Text를 보낼때 받는 쪽의 입장에서도 정확히 그 Text를 받아 보는 것입니다.

    > > 물론 천천히(1초에 한번 정도 SendText를 실행) 보낼때는 SendText가 하나의 단위로 끊어 집니다.

    > >

    > > 아주 빨리 보내더라도 Text가 붙어 버리지 않게 보내는 방법이 없을까요?

    > >

    > > Disk Cache의 경우에는 Flush라는 강제적인 명령이 있는데 Socket 송신 Buffer에 대해서 그런 행동을 하겠끔 하는 메커니즘은 없는가요?

    > >

    > > --------------------------------------------------------------------------------

    > > 참고로

    > > 위의 상황에서 Socket은 Blocking Type이 아닙니다. NonBlocking Type이며 저는 NonBlocking Type에서 위와 같은 일을 하고 싶습니다.

    > > Blocking Type은 안정적이지만 좀 비효율적이라 저는 사용치 않습니다.

    > > 그리고 위와같은 문제는 Blocking Type으로 해도 똑같이 발생할걸로 생각이 됩니다.

    > >

    > >

  • Profile
    밥벌레 2000.08.07 10:46
    일단 델파이 문제는 절대 아님다..

    원래 그런거에요..



    sendtext 라는 녀석은, 말 그대로 text 만 보냅니다..

    문자열 분리 캐릭터 '#13 ' 엔터 같은거를 안보내구요..(물론 명시적으로 붙여 보내면 같이 갑니당)

    게다가 받는쪽에서 처리도..메세지 올때마다 버퍼에 쌓인것을 몽땅 꺼냅니다..

    정확하게 말하면, 메세지 올때마다가 아니고, 버퍼에 뭔가 쌓여 있으면 몽땅 꺼냅니다..만약에 처리 도중에 메세지가 2개 날아오면, 다음에는 2개 한꺼번에 꺼냅니다..

    당연히 쌓이면 붙어 버릴 수 밖에 없는 구조이구요..

    잘라서 보낸다는것은 TCP/IP 소켓에서는 원초적으로 불가능합니당..

    UNIX에서 TCP소켓 처리하는거 보면 아시겠지만, 소켓도 file descripter이고..그래서 스트림입니당..스트림이 잘라질 수 는 없지용..줄줄이 가고..줄줄이 쌓이고..뭐..그런거죠..

    가장 쉬운 해결책은 writeln, readln 함수가 지원되는 컴포넌트를 사용하세요..

    readln 한번 할때마다 한문장씩 짤라서 주니까, 완벽하게 처리 가능합니다..

    sendtext를 써서 분리 하려면 문자열 사이에 구분자를 넣고 잘라주는 작업을 직접 해야 하는데, 쉬운일 아님다..sendtext 안쓰는게 젤 속편해요..

    참고로 저는 winshoes 씁니당..^^

    그럼 즐푸 하셔용~~



    PS. Winshoes 의 서버소켓은 무조건 thread를 만듭니다..즉 블럭킹 되는거죠..사용하기는 쉽습니다만..non blocking 처리는 안됩니다.. 그냥 blocking 처리 하시죠.. 요즘 컴퓨터 성능도 좋은데 효율 따지기 보다는 짜기 쉬운게 낫죠..^^



    Hoon Reader wrote:

    >

    > 도저히 해결 못해서 할 수 없이 도움을 요청합니다.

    > 델파이의 문제 같기도 한데 ...

    >

    > 문제는 이런 겁니다.

    >

    > 보내는 쪽에서는 아래와 같이 For 문을 사용해서 100개의 Text를 보냅니다.

    >

    > For Count := 1 to 100 do

    > XSocket.SendText('Message'+IntToStr(Count)+#10#13);

    >

    > 받는 쪽에서는 해당 메시지마다 Ack를 보냅니다.

    >

    > OnReceive

    > YSocket.SendText('Ack');

    >

    > 그러면 누가 생각하건 간에 보낸쪽은 100개의 Ack를 받아야합니다.

    > 그러니 현실은 그렇지가 못합니다.

    >

    > 받은쪽에서 조사를 해보니 보내는 메시지가 붙어서 도착을 하였습니다.

    >

    > 즉, Message1, Message2, Message3, Message4, ...이렇게 보내어져야 하는데,

    >

    > Message1Message2, Message3, Message4Message5Message6Message7, Message8Message9, ... 처럼 Random하게 붙어서 보내어 집니다.

    >

    > 즉, 받는 입장에서는 아무리 빨리 도착을 해도 끊어져서 제대로 처리가 되는데,

    > 보내는 입장에서는 아주 빨리 보내면 위와 같이 따로 끊어서 보낸 것이 대중없이 붙어서 가버립니다. 위처럼 For 문으로 하지않고

    > XSocket.SendText('Message'+IntToStr(1)+#10#13);

    > XSocket.SendText('Message'+IntToStr(2)+#10#13);

    > XSocket.SendText('Message'+IntToStr(3)+#10#13);

    > ...

    > 이렇게 해도 마찬가지입니다.

    >

    > 이제 분명해진건 SendText가 받는 사람의 입장에서 하나의 OnReceive Event를 발생시키지 않는다는 것입니다.

    >

    > 제가 하고 싶은건 하나의 Text를 보낼때 받는 쪽의 입장에서도 정확히 그 Text를 받아 보는 것입니다.

    > 물론 천천히(1초에 한번 정도 SendText를 실행) 보낼때는 SendText가 하나의 단위로 끊어 집니다.

    >

    > 아주 빨리 보내더라도 Text가 붙어 버리지 않게 보내는 방법이 없을까요?

    >

    > Disk Cache의 경우에는 Flush라는 강제적인 명령이 있는데 Socket 송신 Buffer에 대해서 그런 행동을 하겠끔 하는 메커니즘은 없는가요?

    >

    > --------------------------------------------------------------------------------

    > 참고로

    > 위의 상황에서 Socket은 Blocking Type이 아닙니다. NonBlocking Type이며 저는 NonBlocking Type에서 위와 같은 일을 하고 싶습니다.

    > Blocking Type은 안정적이지만 좀 비효율적이라 저는 사용치 않습니다.

    > 그리고 위와같은 문제는 Blocking Type으로 해도 똑같이 발생할걸로 생각이 됩니다.

    >

    >