Как поддерживать связь между клиентом и сервером - PullRequest
1 голос
/ 27 мая 2019

Я пытаюсь создать свое собственное асинхронное клиент-серверное приложение с использованием сокетов .net.

Используя эти два примера, основные функции работают.

Сервер

Клиент

В этом примере при соединении сервер отправляет строку на сервер, и сервер отвечает, повторяя полученную строку, обратно клиенту.

После этого ответа клиент затем выключается.

// Release the socket.  
client.Shutdown(SocketShutdown.Both);  
client.Close();

В моем сценарии я пытаюсь подключиться к серверу, а затем отправить данные на сервер с клиента с помощью ввода от пользователя.Я отвечаю в ответ <OK>.

В этом примере, который я ссылался выше, клиент всегда ожидает обратного вызова после отправки (следовательно, мой ответ <OK>).

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

Я совершенно уверен, что мне не хватает некоторого основного понимания того, что должно и не должно происходить.

Прямо сейчас я могуотправьте строку, сервер ответит, и клиент получит это <ok>.Затем я пытаюсь отправить другую строку, но сервер никогда не «получает» эту строку.Я полагаю, что сервер теперь также ожидает обратного вызова после отправки строки, но если я возвращаю что-то на сервер после получения клиентской стороны, весь цикл продолжается и повторяется?

Как заставить сервер ждатьчтобы получить больше «новых» данных после ответа, ок?

Должен ли я сказать «снова прослушивать» новые данные?Это похоже на перезапуск соединения, что не является моим намерением ...

Я был бы признателен за понимание того, что мне здесь не хватает ...

(PS сервер подключен с обратным вызовомсобытие при отправке. Я оставил это так, как это было в примере кода, который я связал, реализовал. Должен ли я изменить подпрограммы отправки на сервер? (не ждать обратного вызова)?

Код моего сервера:

          public static void StartListening()
        {
            // Establish the local endpoint for the socket.  
            // The DNS name of the computer  
            // running the listener is "host.contoso.com".  
            IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[1];

            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
            xServerLog.AddLine("Server started: Listening on: " + localEndPoint.Address.ToString());
            xServerLog.ipAddress = localEndPoint.Address.ToString();
            xServerLog.port = port;

            // Create a TCP/IP socket.  
            Socket myTCPserver = new Socket(ipAddress.AddressFamily,
                SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.  
            try
            {
                myTCPserver.Bind(localEndPoint);
                myTCPserver.Listen(100);

                while (true)
                {
                    // Set the event to nonsignaled state.  
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.  
                    Console.WriteLine("Waiting for a connection...");

                    xServerLog.AddLine("Waiting for connections...");

                    myTCPserver.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        myTCPserver);

                    // Wait until a connection is made before continuing.  
                    allDone.WaitOne();
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("\nPress ENTER to continue...");
            xServerLog.AddLine("I think things are done here...");

         //   Console.Read();

        }

        public static void AcceptCallback(IAsyncResult ar)
        {
            // Signal the main thread to continue.  
            allDone.Set();

            // Get the socket that handles the client request.  
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            // Create the state object.  
            StateObject state = new StateObject();
            state.workSocket = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }

        public static void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;

            // Retrieve the state object and the handler socket  
            // from the asynchronous state object.  
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;

            // Read data from the client socket.   
            int bytesRead = handler.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));

                // Check for end-of-file tag. If it is not there, read   
                // more data.  
                content = state.sb.ToString();
                if (content.IndexOf("<EOF>") > -1)
                {
                    // All the data has been read from the   
                    // client. Display it on the console.  
                   // Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                    //    content.Length, content);

                    xServerLog.AddLine("RX:" + content);


                    // Echo the data back to the client.  
                    Send(handler, "<OK>");
                }
                else
                {
                    // Not all data received. Get more.  
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
                }
            }
        }

        private static void Send(Socket handler, String data)
        {
            // Convert the string data to byte data using ASCII encoding.  
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.  
            handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
        }

        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket handler = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.  
                int bytesSent = handler.EndSend(ar);
                //Console.WriteLine("Sent {0} bytes to client.", bytesSent);

                xServerLog.AddLine("TX:OK"); // + bytesSent.ToString() + " bytes to client");

             //   handler.Shutdown(SocketShutdown.Both);
             //   handler.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public void Start()
        {
            StartListening();
            //  return 0;
        }

Код моего клиента :

  class xtcpClient
{

    // State object for receiving data from remote device.  
    public class StateObject
    {
        // Client socket.  
        public Socket workSocket = null;
        // Size of receive buffer.  
        public const int BufferSize = 256;
        // Receive buffer.  
        public byte[] buffer = new byte[BufferSize];
        // Received data string.  
        public StringBuilder sb = new StringBuilder();
    }

    public class AsynchronousClient
    {
        //remote ip port
        //  private static string remoteServerIP = "0.0.0.1";

        private static IPAddress rIP;// = IPAddress.Parse(remoteServerIP);
        private static IPEndPoint remoteEP; // = new IPEndPoint(rIP, port);

        // Create a TCP/IP socket.  
        private static Socket myTCPClient; // = new Socket(rIP.AddressFamily,SocketType.Stream, ProtocolType.Tcp);

        // The port number for the remote device.  
        private static int port; // = 11000;

        // ManualResetEvent instances signal completion.  
        private static ManualResetEvent connectDone =
            new ManualResetEvent(false);
        private static ManualResetEvent sendDone =
            new ManualResetEvent(false);
        private static ManualResetEvent receiveDone =
            new ManualResetEvent(false);

        // The response from the remote device.  
        //  private static String response = String.Empty;

        private static string serverResponse = string.Empty;

        private static void _open_client()
        {

            remoteEP = new IPEndPoint(rIP, port);

            myTCPClient = new Socket(rIP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            // Connect to the remote endpoint.  
            myTCPClient.BeginConnect(remoteEP,
                new AsyncCallback(ConnectCallback), myTCPClient);
            connectDone.WaitOne();
        }

        //////////private static void StartClient(IPAddress remoteIP, int remotePort)
        //////////{
        //////////    // Connect to a remote device.  
        //////////    try
        //////////    {
        //////////        _open_client();
        //////////        //rIP = remoteIP;
        //////////        //port = remotePort;

        //////////        // Establish the remote endpoint for the socket.  
        //////////        // The name of the   
        //////////        // remote device is "host.contoso.com".  
        //////////        //IPHostEntry ipHostInfo = Dns.GetHostEntry("host.contoso.com");
        //////////        //IPAddress ipAddress = ipHostInfo.AddressList[1];

        //////////        // Send test data to the remote device.  
        //////////        //   string sendReply = "";

        //////////        //  sendReply = Send(myTCPClient, "echo 123<EOF>"); //send an initial test echo 
        //////////        //   xClientLog.AddLine("Sent: Echo<EOF>");
        //////////        //  xClientLog.AddLine("Server Replied: " + sendReply);

        //////////        // Write the response to the console.  
        //////////        //  Console.WriteLine("Response received : {0}", response);
        //////////        //  xClientLog.AddLine("Response received: " + response);

        //////////    }
        //////////    catch (Exception e)
        //////////    {
        //////////        Console.WriteLine(e.ToString());
        //////////    }
        //////////}

        public void _close_connection()
        {
            // Release the socket.  
            myTCPClient.Shutdown(SocketShutdown.Both);
            myTCPClient.Close();
        }
        private static string Send(Socket client, String data)
        {

            if (client is null)
            {
                _open_client();
            }


            // Convert the string data to byte data using ASCII encoding.  
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.  
            client.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), client); //fire sendcallback when done sending...

            sendDone.WaitOne();

            // Receive the response from the remote device.  
            Receive(myTCPClient);
            receiveDone.WaitOne();

            return serverResponse; //return server response

        }
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket client = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.  
                int bytesSent = client.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to server.", bytesSent);
                xClientLog.AddLine("Sent bytes to server: " + bytesSent);


                // Signal that all bytes have been sent.  
                sendDone.Set(); //signal the send event to finish, it will start listening for a reply...
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private static void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.  
                Socket client = (Socket)ar.AsyncState;

                // Complete the connection.  
                client.EndConnect(ar);

                Console.WriteLine("Socket connected to {0}",
                    client.RemoteEndPoint.ToString());
                xClientLog.AddLine("Socket connected to: " + client.RemoteEndPoint.ToString());

                // Signal that the connection has been made.  
                connectDone.Set();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        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); //fire receivcallback event when done receining
            }
            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));

                    serverResponse = state.sb.ToString();
                    if (serverResponse.IndexOf("<OK>") > -1) {
                        // All the data has been read from the server
                        xClientLog.AddLine("RX:" + serverResponse);
                        receiveDone.Set();
                    }
                    else
                    {
                        // Get the rest of the data.  
                        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(ReceiveCallback), state);
                    }

                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }



        //public static int Main(String[] args)
        //{
        //    StartClient();
        //    return 0;
        //}
        public void startClient(string remoteIP, int remotePort)
        {
            try
            {
                rIP = IPAddress.Parse(remoteIP);
                port = remotePort;

                _open_client();
            }
            catch (Exception e)
            {

                System.Windows.MessageBox.Show(e.Message + Environment.NewLine + e.InnerException.Message);
            }

        }
        public string sendData(string DataToSend)
        {
            return (Send(myTCPClient, DataToSend));
        }
    }
}

1 Ответ

0 голосов
/ 27 мая 2019

Возможно, потому что каждый вызов на вашем сервере принимает нового клиента.Если вы хотите продолжать принимать в течение неопределенного времени, вы можете попробовать что-то вроде этого, чтобы убедиться, что всегда есть «вызов для принятия», доступный для новых клиентов:

while (true) {
var clientSocket = listeningSocket.Accept();
Task.Factory.StartNew(() => HandleClient(clientSocket));
}

Также возможно, что клиент закрывает соединение.Если сервер закрывает соединение Socket методом Shutdown и все доступные данные были получены, метод Receive завершится и ничего не вернет.

...