如何让客户端和服务器保持通话 [英] How to keep client and server talking

查看:61
本文介绍了如何让客户端和服务器保持通话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 .net 套接字构建我自己的异步客户端/服务器应用程序.

I am trying to build my own asynchronous client/server app using .net sockets.

使用这两个示例,基本功能就起作用了.

Using these two examples, the basic functionality works.

服务器

客户端

这个例子在连接时向服务器发送一个字符串,服务器回复,回显它收到的字符串,返回给客户端.

This example sends a string to the server upon connection, and the server replies, echoing the string that it received, back to the client.

在这个回复之后,客户端然后关闭.

After this reply, the client then shuts down.

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

在我的场景中,我尝试连接到服务器,然后通过用户的输入将数据从客户端发送到服务器.我用 回复.

In my scenario, I am trying to connect to the server and then send data to the server from the client via input from the user. I reply back with <OK>.

在我上面链接的这个例子中,客户端总是在发送后等待回调(因此我的回复是<OK>).

In this example I linked above, the client always waits for a callback after sending (Hence my reply of <OK>).

我没有像示例中那样关闭客户端,因为我想按需发送连续的字符串.我需要服务器一直监听并回复以确认收到字符串.

I am not shutting down the client like in the example, as I want to send consecutive strings on demand. I need the server to keep listening and replying to confirm receipt of string.

我很确定我对应该发生和不应该发生的事情缺少一些核心理解.

I am quite sure I am missing some core understanding of what should and should not happen.

现在,我可以发送一个字符串,服务器回复并且客户端收到这个<ok>.然后我尝试发送另一个字符串,但服务器永远不会接收"这个字符串.我猜服务器在发送字符串后现在也在等待回调,但是如果我在收到客户端后向服务器返回一些东西,整个循环会继续并重复吗?

Right now, I can send a string, the server replies and the client receives this <ok>. I then try to send another string, but the server never "receives" this string. I guess the server is now also waiting for a callback after sending the string, but If I return something to the server after receiving the client side, the whole loop continues and repeats?

如何让我的服务器在回复确定后等待更多新"数据?

How do I make my server wait for more "new" data after replying ok?

我是否必须告诉它再次监听"任何新数据?这似乎是重新启动连接,这不是我的本意...

Do I have to tell it to "listen" again for any new data? This seems like restarting the connection, which is not my intention...

我希望能深入了解我在这里缺少的东西...

I would appreciate some insight into what I am missing here...

(PS 服务器在发送时连接了一个回调事件.我就这样离开了,因为这是我链接、实现的代码示例.我是否必须更改我的服务器发送例程?(不要等待回调)?

(P.S. the server is wired with a callback event when sending. I left it like this as this was what the code example that I linked, implemented. DO I have to change my server send routines? (Not to wait for a callback)?

我的服务器代码:

          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));
        }
    }
}

推荐答案

可能是因为服务器上的每个接受调用"都会接受一个新客户端.如果您想无限期地继续接受,您可以尝试这样的方法,以确保新客户始终可以接受接受":

Probably because each 'call to accept' on your server accepts a new client. If you want to keep accepting indefinitely you can try something like this to make sure there is always a 'call to accept' available for new clients:

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

也有可能是客户端关闭了连接.如果服务端使用 Shutdown 方法关闭了 Socket 连接,并且所有可用的数据都已经收到,那么 Receive 方法将完成并且什么都不返回.

It's also possible that the client closes the connection. If the server shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete and return nothing.

这篇关于如何让客户端和服务器保持通话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆