Delphi에서 비동기 소켓 프로그래밍을 수행하는 관용적인 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/37185

문제

Delphi에서 네트워크 코드를 작성하는 사람들이 Windows 스타일 중첩 비동기 소켓 I/O를 사용하는 일반적인 방법은 무엇입니까?

이 질문에 대한 나의 이전 연구는 다음과 같습니다.

그만큼 인디 구성 요소는 완전히 동기식으로 보입니다.반면 ScktComp 장치는 WSAAsyncSelect를 사용하지만 기본적으로 BSD 스타일 멀티플렉싱 소켓 앱만 비동기화합니다.마치 루프의 select()에서 방금 반환된 것처럼 단일 이벤트 콜백에 덤프되고 모든 상태 머신 탐색을 직접 수행해야 합니다.

.NET 상황은 Socket.BeginRead/Socket.EndRead를 사용하여 훨씬 더 좋습니다. 여기서 연속은 Socket.BeginRead로 직접 전달되며 여기서 다시 시작합니다.클로저로 코딩된 연속에는 필요한 모든 컨텍스트와 그 이상이 포함됩니다.

도움이 되었습니까?

해결책

비동기 작업의 경우 ICS를 사용해 보세요.

http://www.overbyte.be/frame_index.html?redirTo=/products/ics.html

다른 팁

처음에는 Indy가 더 간단한 개념이었지만 응용 프로그램 종료 시 스레드를 해제하기 위해 소켓을 종료해야 하기 때문에 관리하기가 어색하다는 사실을 발견했습니다.게다가 OS 패치 업그레이드 이후 Indy 라이브러리의 작동이 중단되었습니다.ScktComp는 내 응용 프로그램에 잘 작동합니다.

@Roddy - 동기 소켓은 내가 추구하는 것이 아닙니다.수명이 긴 연결을 위해 전체 스레드를 굽는 것은 동시 연결의 양을 프로세스에 포함될 수 있는 스레드 수로 제한한다는 의미입니다.스레드는 많은 리소스(예비된 스택 주소 공간, 커밋된 스택 메모리, 컨텍스트 전환을 위한 커널 전환)를 사용하므로 수백 개, 수천 개 이상의 연결을 지원해야 할 때 확장되지 않습니다.

Delphi에서 네트워크 코드를 작성하는 사람들이 Windows 스타일 중첩 비동기 소켓 I/O를 사용하는 일반적인 방법은 무엇입니까?

Indy는 오랫동안 소켓 I/O의 '표준' 라이브러리였으며 블로킹 소켓을 기반으로 합니다.즉, 비동기식 동작을 원할 경우 추가 스레드를 사용하여 데이터를 연결/읽기/쓰기합니다.내 생각에는 이것이 실제로 큰 장점입니다. 어떤 종류의 상태 머신 탐색도 관리할 필요가 없고 콜백 절차나 이와 유사한 것에 대해 걱정할 필요도 없기 때문입니다.나는 내 '읽기' 스레드의 논리가 비차단 소켓이 허용하는 것보다 덜 복잡하고 이식성이 훨씬 더 높다는 것을 알았습니다.

인디 9 우리에게는 대부분 방폭형이고 빠르고 안정적이었습니다.그러나 Tiburon을 Indy 10으로 전환하면서 약간의 우려가 생겼습니다.

@마이크:"...스레드를 해제하려면 소켓을 종료해야 합니다...".

이것은 "허?" 스레딩 라이브러리는 예외 기반 기술을 사용하여 '대기'스레드를 안전하게 죽이는 것을 기억할 때까지.우리는 전화한다 대기열사용자APC 스레드 래퍼 프로시저에서만 포착해야 하는 C++ 예외(Exception 클래스에서 파생되지 않음)를 발생시키는 함수를 대기열에 추가합니다.모든 소멸자가 호출되어 스레드가 모두 깔끔하게 종료되고 나가는 길에 정리됩니다.

"동기 소켓은 내가 추구하는 것이 아닙니다."

이해합니다. 하지만 이 경우 원래 질문에 대한 대답은 Delphi가 없다는 것입니다. 관용구 비동기 소켓 IO의 경우 실제로는 매우 전문적이고 흔하지 않은 요구 사항이기 때문입니다.

부수적인 문제로 이러한 링크가 흥미로울 수도 있습니다.둘 다 조금 오래되었고 Windows보다 *nxy가 더 많습니다.두 번째는 올바른 환경에서 스레드가 생각만큼 나쁘지 않을 수 있음을 의미합니다.

C10K 문제

이벤트가 나쁜 생각인 이유(고동시 서버의 경우)

@Chris Miller-답변에 언급하신 내용은 실제로 부정확합니다.

WSAAsyncSelect를 통해 사용할 수 있는 Windows 메시지 스타일 비동기는 실제로 Win 3.x 시대에 적절한 스레딩 모델이 부족한 것에 대한 해결 방법입니다.

그러나 .NET 시작/끝은 ~ 아니다 추가 스레드를 사용합니다.대신 WSASend/WSARecv의 추가 인수, 특히 중첩 완료 루틴을 사용하여 연속을 지정하는 중첩 I/O를 사용합니다.

이는 .NET 스타일이 Windows OS의 비동기 I/O 지원을 활용하여 피하다 소켓을 차단하여 스레드를 태우는 것입니다.

스레드는 일반적으로 비용이 많이 들기 때문에(CreateThread에 매우 작은 스택 크기를 지정하지 않는 한) 소켓에서 스레드를 차단하면 동시 연결 수를 10,000개로 확장할 수 없습니다.

이것이 바로 확장을 원하는 경우 비동기 I/O를 사용하는 것이 중요한 이유이며, .NET이 ~ 아니다, 반복합니다. ~ 아니다, 단순히 "스레드를 사용하여 [...] 프레임워크에서 관리하는 것"입니다.

@Roddy - 귀하가 가리키는 링크를 이미 읽었으며 둘 다 Paul Tyma의 프레젠테이션 "수천 개의 스레드 및 차단 I/O - Java 서버를 작성하는 이전 방법이 다시 새로워졌습니다"에서 참조되었습니다.

그러나 Paul의 프리젠테이션에서 반드시 튀어나올 필요는 없는 몇 가지 사항은 그가 시작 시 JVM에 -Xss:48k를 지정했으며 JVM의 NIO 구현이 유효하기 위해 효율적이라고 가정하고 있다는 것입니다. 비교.

인디는 그렇습니다 ~ 아니다 비슷하게 축소되고 엄격하게 제한된 스택 크기를 지정합니다.Indy 코드베이스에는 BeginThread(이러한 상황에 사용해야 하는 Delphi RTL 스레드 생성 루틴) 또는 CreateThread(원시 WinAPI 호출)에 대한 호출이 없습니다.

기본 스택 크기는 PE에 저장되며, 델파이 컴파일러의 경우 기본값은 1MB의 예약된 주소 공간입니다(공간은 OS에 의해 페이지별로 4K 청크로 커밋됩니다.실제로 확장 기능은 페이지 오류에 의해 제어되지만 스택의 가장 낮은(보호) 페이지에 대해서만 제어되기 때문에 함수에 로컬이 4K를 초과하는 경우 컴파일러는 페이지를 터치하는 코드를 생성해야 합니다.즉, 최대 2,000개의 동시 스레드가 연결을 처리하면 주소 공간이 부족해집니다.

이제 {$M minStackSize [,maxStackSize]} 지시문을 사용하여 PE의 기본 스택 크기를 변경할 수 있지만 이는 영향을 미칩니다. 모두 메인 스레드를 포함한 스레드.48K 또는 (유사한) 공간이 많지 않기 때문에 많은 재귀를 수행하지 않기를 바랍니다.

이제 특히 Windows용 비동기 I/O의 성능 저하에 대한 Paul의 말이 맞는지 여부는 100% 확신할 수 없습니다. 확실히 하려면 이를 측정해야 합니다.그러나 내가 아는 것은 스레드 프로그래밍이 비동기 이벤트 기반 프로그래밍보다 쉽다는 주장이 잘못된 이분법.

비동기 코드는 그렇지 않습니다 필요 이벤트 기반이어야 합니다..NET에서처럼 연속 기반일 수 있으며, 연속으로 클로저를 지정하면 상태가 무료로 유지됩니다.또한 선형 스레드 스타일 코드에서 연속 전달 스타일 비동기 코드로의 변환은 컴파일러에 의해 기계적으로 수행될 수 있으므로(CPS 변환은 기계적으로 수행됨) 코드 명확성에 대한 비용도 필요하지 않습니다.

무료 IOCP(완료 포트) 소켓 구성 요소가 있습니다. http://www.torry.net/authorsmore.php?id=7131 (소스코드 포함)

"나베레그니 세르게이 N..Windows 완료 포트를 기반으로하는 고성능 소켓 서버 및 Windows 소켓 확장 기능을 사용합니다.IPv6 지원."

내 작은 인스턴트 메시징 서버를 재구성하기 위해 더 나은 구성 요소/라이브러리를 찾는 동안 그것을 발견했습니다.아직 시도하지는 않았지만 첫인상으로는 코딩이 잘 된 것 같습니다.

Indy는 프로그래밍이 더 간단하기 때문에 동기식 소켓을 사용합니다.비동기 소켓 차단은 Windows 3.x 시절에 Winsock 스택에 추가된 것입니다.Windows 3.x는 스레드를 지원하지 않았으며 스레드 없이는 소켓 I/O를 수행할 수 없었습니다.Indy가 차단 모델을 사용하는 이유에 대한 추가 정보는 다음을 참조하세요. 이 기사.

.NET Socket.BeginRead/EndRead 호출은 스레드를 사용하고 있으며 이는 사용자가 아닌 Framework에 의해 관리됩니다.

@Roddy, Indy 10은 Delphi 2006부터 Delphi와 번들로 제공되었습니다.저는 Indy 9에서 Indy 10으로 마이그레이션하는 것이 간단한 작업이라는 것을 알았습니다.

ScktComp 클래스를 사용하면 NonBlocking 서버 유형이 아닌 ThreadBlocking 서버를 사용해야 합니다.OnGetThread 이벤트를 사용하여 ClientSocket 매개변수를 고안의 새 스레드에 전달합니다.TServerClientThread의 상속된 인스턴스를 인스턴스화한 후에는 소켓을 읽고 쓰는 데 사용할 수 있는 TWinSocketStream(스레드 내부)의 인스턴스를 생성하게 됩니다.이 방법을 사용하면 이벤트 핸들러에서 데이터를 처리하지 않아도 됩니다.이러한 스레드는 읽거나 쓰는 데 필요한 짧은 기간 동안만 존재할 수도 있고, 재사용을 위해 잠시 동안 유지될 수도 있습니다.

소켓 서버 작성의 주제는 상당히 광범위합니다.구현하기 위해 선택할 수 있는 기술과 방법이 많이 있습니다.TServerClientThread에서 동일한 소켓을 읽고 쓰는 방법은 간단하고 간단한 애플리케이션에 적합합니다.고가용성 및 높은 동시성을 위한 모델이 필요한 경우 Proactor 패턴과 같은 패턴을 조사해야 합니다.

행운을 빌어요!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top