Я хочу, чтобы кнопка событие, когда обратный вызов получен
в моем коде 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); }
Что я уже пробовал:
я попробовал обработчик событий и сделать поток внутри обратного вызова, чтобы выйти из сервера
и это вовсе не работа..
я думаю, что приоритет события, слушателя и обратного вызова-это проблема.
я знаю, что слушатель является высокоприоритетным следующим обратным вызовом последнего события