2010-03-27 4 views
3

C#에서 비동기 소켓 메서드를 사용하는 올바른 방법에 대해 혼란스러워합니다. 나는이 두 기사를 참조하여 내 질문을한다 : MSDN article on asynchronous client socketsdevarticles.com article on socket programming.C#의 비동기 소켓

내 질문에 대한 답변은 BeginReceive()입니다. MSDN 문서는 수신 데이터를 처리하기 위해이 두 가지 기능을 사용하십시오 devarticles.com 튜토리얼이 BeginReceive 방법의 마지막 매개 변수에 대한 null를 전달하는 동안

private static void Receive(Socket client) 
{ 
    try 
    { 
    // Create the state object. 
    StateObject state = new StateObject(); 
    state.workSocket = client; 

    // Begin receiving the data from the remote device. 
    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(ReceiveCallback), state); 
    } 
    catch (Exception e) 
    { 
    Console.WriteLine(e.ToString()); 
    } 
} 

private static void ReceiveCallback(IAsyncResult ar) 
{ 
    try 
    { 
    // Retrieve the state object and the client socket 
    // from the asynchronous state object. 
    StateObject state = (StateObject) ar.AsyncState; 
    Socket client = state.workSocket; 
    // Read data from the remote device. 
    int bytesRead = client.EndReceive(ar); 
    if (bytesRead > 0) 
    { 
     // There might be more data, so store the data received so far. 
     state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); 
     // Get the rest of the data. 
     client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, 
      new AsyncCallback(ReceiveCallback), state); 
    } 
    else 
    { 
     // All the data has arrived; put it in response. 
     if (state.sb.Length > 1) 
     { 
     response = state.sb.ToString(); 
     } 
     // Signal that all bytes have been received. 
     receiveDone.Set(); 
    } 
    } 
    catch (Exception e) 
    { 
    Console.WriteLine(e.ToString()); 
    } 
} 

을하고, 마지막 매개 변수는 우리가 '할 때 유용하다는 것을 설명하기 위해 계속 여러 개의 소켓을 다루고 있습니다. 이제 내 질문은 :

  1. 우리는 단지 하나의 소켓에 작업하는 경우 BeginReceive 방법에 상태를 전달하는 점은 무엇입니까? 클래스 필드 사용을 피하는 것입니까? 그것을하는 데는 작은 점이있는 것처럼 보이지만, 아마도 나는 뭔가를 놓치고 있습니다.

  2. 여러 소켓을 처리 할 때 상태 매개 변수가 어떻게 도움이 될 수 있습니까? client.BeginReceive(...)이라면 client 소켓에서 모든 데이터를 읽을 수 있습니까? devarticles.com 튜토리얼은이 호출에 같은 소리한다 : m_asynResult = m_socClient.BeginReceive (theSocPkt.dataBuffer,0,theSocPkt.dataBuffer.Length, SocketFlags.None,pfnCallBack,theSocPkt);

데이터 대신 m_socClient 소켓에서의, theSocPkt.thisSocket 소켓에서 읽을 수 있습니다. 그들의 예에서 두 개는 동일하고 동일하지만, 그렇지 않은 경우 어떻게됩니까?

필자는 마지막 인수가 유용하거나 적어도 여러 소켓에서 어떻게 도움이되는지 실제로 알지 못합니다. 소켓이 여러 개있는 경우 각각 BeginReceive으로 전화해야합니다. 맞습니까?

답변

2

단일 소켓으로 만 작업하는 경우 BeginReceive 메서드에 상태를 전달하는 점은 무엇입니까? 클래스 필드 사용을 피하는 것입니까? 그것을하는 데는 작은 점이있는 것처럼 보이지만, 아마도 나는 뭔가를 놓치고 있습니다.

당신이 그 상태를 사용하지 않았다면 회원을 대신 사용해야 할 것입니다. 그러나이 변수는 상태 변수보다 지역 변수가 적습니다. 지역적인 사항이 많을수록 코드의 다른 부분을 변경할 때 깨지기 쉬워집니다.

일반적인 메소드 호출과 비교하십시오. 매개 변수를 멤버로 설정 한 다음 매개 변수없이 모든 함수를 호출하면 어떨까요? 그것은 작동하지만 ... 코드를 읽는 것은 끔찍할 것입니다. 범위를 가능한 한 로컬로 유지함으로써 디자인을 더 쉽게 이해하고 수정할 수 있습니다. 캡슐화가 개선되면 더 강력한 코드가 생성됩니다.

동일하게 적용됩니다. asyncoronous callback이 하나뿐이라면 클래스에 멤버를 설정하는 것만으로 도망 갈 수는 있지만 그러한 호출이 많으면 위에 언급 한 것과 비슷한 문제가 발생할 수 있습니다. 혼란스럽고 깨지기 쉬운 코드입니다.

여러 소켓을 처리 할 때 상태 매개 변수는 어떻게 도움이 될 수 있습니까?

각 호출마다 각각 다른 클라이언트 객체를 포함하는 다른 상태 객체를 전달할 수 있습니다.클라이언트가 상태에서, 회원이 변수에서 가져온 것을 참고 :

//Socket client = this.client; // Don't do this. 
Socket client = state.workSocket; 

당신은 MSDN 문서의 모든 다른 방법을 통지하는 경우

는 매개 변수로 클라이언트를 취할. 상태는 메소드 서명이 고정되어 있기 때문에 매개 변수를 전달하는 방법 일뿐입니다.


업데이트 :하지가 ArgumentException를 throw하는 경우 올바른 클라이언트 객체를 사용하여 의견, .NET 검사의 질문에 대해서는.

if ((result == null) || (result.AsyncObject != this)) 
{ 
    throw new ArgumentException(SR.GetString("net_io_invalidasyncresult"), "asyncResult"); 
} 
+0

그리고 프로그래머는 상태 객체에 포함 된 소켓이 'BeginReceive'가 호출 된 소켓 객체와 똑같은지 확인해야합니다. 맞습니까? 나는 그들이 다른지, 그것이 오류를 일으킬 것 같아요. – IVlad

+0

필수 사항은 아닙니다. .NET을 사용하면 여러 통화가 동시에 발생하더라도 상태를 안정적으로 전송할 수 있습니다. 일반 함수를 호출 할 때받은 매개 변수가 호출하는 데 사용 된 호출자와 동일한 객체인지 점검 할 필요가 없습니다. 그렇게했다면 매개 변수를 전달할 수 있다는 것은 실용적인 가치가 없습니다. 원본 개체를 비교하기 위해서는 원본 개체를 참조해야하기 때문입니다. –

+0

그건 내가 의미하는 것이 아닙니다. 예를 들어 이것을'BeginReceive' 콜백 함수 안에'Socket client = state.workSocket; 'state.workSocket = B'을 수행 한 후'StateObject state'를 전달하는'BeginReceive '라는 소켓'A'를 생각해보십시오. 이것은'A == B' 인 경우에만 유효합니다. 맞습니까? 나는 모든 예제가 receive 메소드를 호출하는 데 사용 된 상태로 동일한 소켓을 전달하기 때문에 약간 혼란 스럽다. 그러나 둘 다 똑같이 명시해야한다고 명시하지 않았다. 나는 그들이해야한다고 생각하지만, 이것이 사실인지 확인하고 싶습니다. – IVlad

1

어떻게 여러 소켓 상태 매개 변수의 도움을 처리 할 수있을 때 : .NET 리플렉터 디 컴파일의 EndReceive에서 우리는이 볼 수?

여기서 오해는 상태 매개 변수가 정확히 무엇인지에 관한 것입니다. 호출 할 때 : 물론

client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
    ReceiveCallback, state); 

사이트에 당신은 전화가 만든 무엇 '클라이언트 호출이 분명하게,하지만 ReceiveCallback 메서드를 호출 할 때, 그 방법은 클라이언트를 알 수있는 방법이 없습니다 . 서로 다른 소켓에있는 많은 수령은 동시에 진행될 수 있으며, 모두 동일한 콜백 핸들러를 공유하여 결과를 처리합니다.

데이터를 state 매개 변수로 전달할 때 콜백에 추가 컨텍스트를 전달하여 (이 경우) 수신을 시작한 소켓을 파악할 수 있습니다.

상태 매개 변수에 '잘못된 값'을 전달하면 콜백이 사용자를 보호하기 위해 수행 할 수있는 작업이 없습니다. 결과는 상태의 데이터로 수행하는 작업에 따라 달라집니다. 최악의 경우 상태가 실제로 사용되지 않는다면 차이를 만들 수 없습니다. 잘못된 소켓에서 온 것처럼 데이터를 처리 할 수 ​​있으며 상황에 따라 '모든 게시물 삭제'명령을 실행할 수 있습니다. 요청하지 않은 계정의 하지만 다른 프로그래밍 버그와 다르지 않습니다.)

관련 문제