brockeu Ответов: 1

Я хочу, чтобы кнопка событие, когда обратный вызов получен


в моем коде soket получает aync. и при получении обратного вызова есть отправить сообщение.

так что обратный вызов всегда зацикливается.

получено-отправлено-получено-отправлено .......

в этой ситуации, как я могу прервать этот цикл и выйти.

я делаю кнопку выхода, но она не работает. только я нажимаю быстро много раз.

public class AsyncObject
{
    public Byte[] Buffer;
    public Socket WorkingSocket;
    public AsyncObject(Int32 bufferSize)
    {
        Buffer = new Byte[bufferSize];
    }
}

private Socket _mServerSocket;
private Socket _mSend;
private AsyncCallback _mFnReceiveHandler;
private AsyncCallback _mFnSendHandler;
private AsyncCallback _mFnAcceptHandler;
public void StartServer()
{
    if (_mServerSocket != null)
    {
        if (_mServerSocket.Connected)
        {
            SetText(richTextBox1, "이미 연결되어있습니다.\n");

        }
        SetText(richTextBox1, "이미 연결되어있습니다.\n");
        return;
    }

    // 비동기 작업에 사용될 대리자를 초기화합니다.
    _mFnReceiveHandler = HandleDataReceive;
    _mFnSendHandler = HandleDataSend;
    _mFnAcceptHandler = HandleClientConnectionRequest;

    // TCP 통신을 위한 소켓을 생성합니다.
    _mServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    // 특정 포트에서 모든 주소로부터 들어오는 연결을 받기 위해 포트를 바인딩합니다.
    // 사용한 포트: 8234
    _mServerSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.0.201"), 8234));
    // 연결 요청을 받기 시작합니다.
    _mServerSocket.Listen(5);

    // BeginAccept 메서드를 이용해 들어오는 연결 요청을 비동기적으로 처리합니다.
    // 연결 요청을 처리하는 함수는 handleClientConnectionRequest 입니다.
    SetText(richTextBox1, "연결중입니다.\n");
    _mServerSocket.BeginAccept(_mFnAcceptHandler, _mServerSocket);

}

public void StopServer(object sender, EventArgs e)
{
    //Thread.Sleep(1000);
    _isClose = true;
    if (_mServerSocket != null)
    {
        if (_mServerSocket.Connected || _mServerSocket.IsBound)
            _mServerSocket.Close();
        _mServerSocket = null;
    }
    if (_mSend != null)
    {
        if (_mSend.Connected)
        {
            _mSend.Disconnect(true);
            _mSend.Close();
        }
        _mSend = null;
    }

    SetText(richTextBox1, "서버가 닫혔습니다.\n");
}

public void SendMessage(String message)
{
    // 추가 정보를 넘기기 위한 변수 선언
    // 크기를 설정하는게 의미가 없습니다.
    // 왜냐하면 바로 밑의 코드에서 문자열을 유니코드 형으로 변환한 바이트 배열을 반환하기 때문에
    // 최소한의 크기르 배열을 초기화합니다.
    if(_mSend == null) return;
    if (message.Length==0) return;
    string sendmessage = message + "\n";
    var ao = new AsyncObject(1) { Buffer = Encoding.UTF8.GetBytes(sendmessage), WorkingSocket = _mSend };
    try
    {
        // 전송 시작!
        _mSend.BeginSend(ao.Buffer, 0, ao.Buffer.Length, SocketFlags.None, _mFnSendHandler, ao);
    }
    catch (SocketException secException)
    {
        MessageBox.Show(secException.ToString());
    }

}

private void HandleClientConnectionRequest(IAsyncResult ar)
{
    try
    {
        // 클라이언트의 연결 요청을 수락합니다.
        Socket sockClient = _mServerSocket.EndAccept(ar);
        _mSend = sockClient;
        // 4096 바이트의 크기를 갖는 바이트 배열을 가진 AsyncObject 클래스 생성
        var ao = new AsyncObject(4096);
        SetText(richTextBox1, sockClient.RemoteEndPoint + "의 연결 요청 수락\n");
        // 작업 중인 소켓을 저장하기 위해 sockClient 할당
        ao.WorkingSocket = sockClient;
        _isClose = false;

        // 비동기적으로 들어오는 자료를 수신하기 위해 BeginReceive 메서드 사용!
        sockClient.BeginReceive(ao.Buffer, 0, ao.Buffer.Length, SocketFlags.None, _mFnReceiveHandler, ao);
    }
    catch (ObjectDisposedException)
    {
    }
    catch (SocketException)
    {
    }
    catch (NullReferenceException)
    {
    }
}
private void HandleDataReceive(IAsyncResult ar)
{
    try
    {

        // 넘겨진 추가 정보를 가져옵니다.
        // AsyncState 속성의 자료형은 Object 형식이기 때문에 형 변환이 필요합니다~!
        var ao = (AsyncObject) ar.AsyncState;

        // 자료를 수신하고, 수신받은 바이트를 가져옵니다.
        Int32 recvBytes = ao.WorkingSocket.EndReceive(ar);
        if (!ao.WorkingSocket.Connected) return;
        // 수신받은 자료의 크기가 1 이상일 때에만 자료 처리
        if (recvBytes > 0)
        {
            SetText(richTextBox1, "메세지 받음: " + Encoding.UTF8.GetString(ao.Buffer));
            SetText(richTextBox1, "\n");
        }
        // 자료 처리가 끝났으면~
        // 이제 다시 데이터를 수신받기 위해서 수신 대기를 해야 합니다.
        // Begin~~ 메서드를 이용해 비동기적으로 작업을 대기했다면
        // 반드시 대리자 함수에서 End~~ 메서드를 이용해 비동기 작업이 끝났다고 알려줘야 합니다!
        ar.AsyncWaitHandle.WaitOne();
        Array.Clear(ao.Buffer, 0, ao.Buffer.Length);
        ao.WorkingSocket.BeginReceive(ao.Buffer, 0, ao.Buffer.Length, SocketFlags.None, _mFnReceiveHandler, ao);
        SendMessage("READ?");
    }
    catch (ObjectDisposedException)
    {
    }
    catch (SocketException)
    {
    }
}

private void HandleDataSend(IAsyncResult ar)
{

    // 넘겨진 추가 정보를 가져옵니다.
    var ao = (AsyncObject)ar.AsyncState;

    // 자료를 전송하고, 전송한 바이트를 가져옵니다.
    Int32 sentBytes = ao.WorkingSocket.EndSend(ar);

    if (sentBytes > 0)
        SetText(richTextBox1, "메세지 보냄: " + Encoding.UTF8.GetString(ao.Buffer));
}

private void Send_Click(object sender, EventArgs e)
{
    string message = richTextBox2.Text;
    SendMessage(message);
}


Что я уже пробовал:

я попробовал обработчик событий и сделать поток внутри обратного вызова, чтобы выйти из сервера
и это вовсе не работа..
я думаю, что приоритет события, слушателя и обратного вызова-это проблема.
я знаю, что слушатель является высокоприоритетным следующим обратным вызовом последнего события

1 Ответов

Рейтинг:
2

Member 10062432

попробуйте избавиться от объектов сервера и сокета в кнопке закрытия.
также добавить

поймать(исключение бывший)
{

MessageBox.Show(ex.Tostring);


}

// чтобы поймать, если он выбрасывает какие-либо другие неизвестные исключения