none
Асинхронный сокет RRS feed

  • Общие обсуждения

  • Делаю клиент - сервер по этому уроку Все работает, но если запустить отправку данных в цикле вот так например:
    Код C#
    1
    2
    3
    4
    
    while (true)
        {
            Cl.SendAsync("Привет, я клиент");
        }
    То где то на второй итерации цикла в методе
    Код C#
    1
    
    ReceiveAsync(SocketAsyncEventArgs e)
    возникает исключение "Выполняется асинхронная операция сокета, используя этот экземпляр SocketAsyncEventArgs"
    Т.е. как я понимаю, клиент пытается получить данные с сервера, когда еще идет отправка данных.

    А если сделать вот так:
    Код C#
    1
    2
    3
    4
    5
    
    while (true)
        {
            Cl.SendAsync("Привет, я клиент");
    Thread.Sleep(200);
        }
    То исключений не возникает. Почему так?

    Собственно вопрос: При асинхронном сокете получение ответа обязательно? Можно ли сделать так что бы клиент только отправлял, а сервер получал, без всяких ответов. Я хочу добиться того, чтобы клиент непрерывно отправлял данные на сервер.

Все ответы

  • Вы используете один SocketAsyncEventArgs объект в двух одновременных операциях, что и приводит к исключению. Чтобы понять, почему так происходит нужно видеть Ваш код.
  • Клиент

    var client = new Client(); client.ConnectAsync("192.168.1.10", 11000); Random r = new Random(); while (true) {

    //Если отправлять данные непрерывно без паузы то будит исключение, а если задерживать паузой то исключения не будит client.SendAsync(r.Next(0,10).ToString()); Thread.Sleep(100); }

    class Client
        {
            private Socket socket;
            private SocketAsyncEventArgs sockAsyncArgs;
            private byte[] buff;

            public Client()
            {
                buff = new byte[1024];
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sockAsyncArgs = new SocketAsyncEventArgs();
                sockAsyncArgs.Completed += SockAsyncArgs_Completed;
            }

            void SockAsyncArgs_Completed(object sender, SocketAsyncEventArgs e)
            {
                switch (e.LastOperation)
                {
                    case SocketAsyncOperation.Connect:
                        ProcessConnect(e);
                        break;
                    case SocketAsyncOperation.Receive:
                        ProcessReceive(e);
                        break;
                    case SocketAsyncOperation.Send:
                        ProcessSend(e);
                        break;
                }
            }

            public void ConnectAsync(string Address, int Port)
            {
                IPAddress ipAddress = Dns.GetHostAddresses(Address)[0];
                IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, Port);
                sockAsyncArgs.RemoteEndPoint = ipLocalEndPoint;
                ConnectAsync(sockAsyncArgs);
            }
            private void ConnectAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.ConnectAsync(e);
                if (!willRaiseEvent)
                    ProcessConnect(e);
            }

            private void ProcessConnect(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    Console.WriteLine("Cервер {0} подключен", e.RemoteEndPoint.ToString());
                    sockAsyncArgs.SetBuffer(buff, 0, buff.Length);
                }
                else
                {
                    Console.WriteLine("Подключиться к серверу {0} не удалось", e.RemoteEndPoint.ToString());
                }
            }

            public void SendAsync(string data)
            {
                if (socket.Connected && data.Length > 0)
                {
                    byte[] buff = Encoding.UTF8.GetBytes(data);
                    SocketAsyncEventArgs e = new SocketAsyncEventArgs();
                    e.SetBuffer(buff, 0, buff.Length);
                    e.Completed += SockAsyncArgs_Completed;
                    SendAsync(e);
                }
            }
            private void SendAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.SendAsync(e);
                if (!willRaiseEvent)
                    ProcessSend(e);
            }

            private void ProcessSend(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    ReceiveAsync(sockAsyncArgs);
                }
                else
                {
                    Console.WriteLine("Dont send");
                }
            }
            private void ReceiveAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.ReceiveAsync(e);
                if (!willRaiseEvent)
                    ProcessReceive(e);
            }

            private void ProcessReceive(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                    Console.WriteLine("Receive: {0}", str);
                }
                else
                {
                    Console.WriteLine("Dont recieve");
                }
            }
        }

    Сервер

    class Server
        {
            // сокет
            private Socket socket;
            // данные для асинхронной операции на сокете
            private SocketAsyncEventArgs acceptAsyncArgs;
            private RichTextBox textBox;
    
            public Server(ref RichTextBox tb)
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                
                acceptAsyncArgs = new SocketAsyncEventArgs();
                
                //событие - завершение асинхронной операции
                acceptAsyncArgs.Completed += AcceptCompleted;
    
                this.textBox = tb;
            }
    
            public void Start()
            {
                socket.Bind(new IPEndPoint(IPAddress.Any, 11000));
                socket.Listen(50);
                AcceptAsync(acceptAsyncArgs);
            }
    
            public void Stop()
            {
                socket.Close();
            }
    
            private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    var client = new ClientConnection(ref textBox, e.AcceptSocket);
                }
                e.AcceptSocket = null;
                AcceptAsync(acceptAsyncArgs);
            }
            private void AcceptAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.AcceptAsync(e);
                if (!willRaiseEvent)
                    AcceptCompleted(socket, e);
            }
        }
    
    class ClientConnection
        {
            //ip клиента
            private EndPoint clientIp;
            private Socket socket;
            private SocketAsyncEventArgs sockAsyncEventArgs;
            private byte[] buff;
            private RichTextBox textBox;
    
            public ClientConnection(ref RichTextBox tb, Socket AcceptedSocket)
            {
                buff = new byte[1];
                socket = AcceptedSocket;
                clientIp = socket.RemoteEndPoint;
                sockAsyncEventArgs = new SocketAsyncEventArgs();
                sockAsyncEventArgs.Completed += SockAsyncEventArgs_Completed;
                sockAsyncEventArgs.SetBuffer(buff, 0, buff.Length);
                this.textBox = tb;
                
                SetTextSafe(String.Format("Подключение клиента: {0}\n", clientIp.ToString()));
    
                ReceiveAsync(sockAsyncEventArgs);
            }
    
            private void SockAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
            {
                switch (e.LastOperation)
                {
                    case SocketAsyncOperation.Receive:
                        ProcessReceive(e);
                        break;
                    case SocketAsyncOperation.Send:
                        ProcessSend(e);
                        break;
                }
            }
    
            private void ProcessSend(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                    ReceiveAsync(sockAsyncEventArgs);
            }
    
            private void ProcessReceive(SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                    SetTextSafe(String.Format("Входящее сообщение от {0}: {1}\n", clientIp.ToString(), str));
                    SendAsync("You send " + str);
                }
            }
    
            private void ReceiveAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.ReceiveAsync(e);
                if (!willRaiseEvent)
                    ProcessReceive(e);
            }
            private void SendAsync(string data)
            {
                byte[] buff = Encoding.UTF8.GetBytes(data);
                SocketAsyncEventArgs e = new SocketAsyncEventArgs();
                e.Completed += SockAsyncEventArgs_Completed;
                e.SetBuffer(buff, 0, buff.Length);
                SendAsync(e);
            } 
            private void SendAsync(SocketAsyncEventArgs e)
            {
                bool willRaiseEvent = socket.SendAsync(e);
                if (!willRaiseEvent)
                    ProcessSend(e);
            }
    
            void SetTextSafe(string newText)
            {
                if (textBox.InvokeRequired) textBox.Invoke(new Action<string>((s) => textBox.AppendText(s)), newText);
                else textBox.AppendText(newText);
            }
        }


  • У Вас метод ProcessSend вызывает ReceiveAsync(sockAsyncEventArgs). Повторный вызов ProcessSend повторно вызовет ReceiveAsync на том же объекте sockAsyncEventArgs, что приведёт к исключению, если предыдущая операция, использующая этот объект, ещё не завершилась.
  • А как сделать чтобы ProcessSend ждал пока завершится операция?