客户端仅在关闭时接收数据包

时间:2013-05-15 17:33:27

标签: c# sockets packet

基本上我制作了两个C#应用程序,一个客户端和一个服务器。客户端连接到服务器(通过套接字),然后发送包含一些文本的数据包,服务器应该回复。 我的问题是:服务器仅在关闭时发送(或客户端接收)响应数据包(ALT + F4)。我想要一些帮助。我将在两个项目的源代码下面进行copypaste。 客户端:

public class StateObject
{
    public Socket skt = null;
    public const int BufferSize = 256;
    public byte[] buffer = new byte[BufferSize];
    public StringBuilder sb = new StringBuilder();
}

public class AsynchronousClient
{
    private const int port = 11000;
    private static ManualResetEvent connectDone =
        new ManualResetEvent(false);
    private static ManualResetEvent sendDone =
        new ManualResetEvent(false);
    private static ManualResetEvent receiveDone =
        new ManualResetEvent(false);
    private static String response = String.Empty;
    public static string command;
    public static Socket client;
    public static void StartClient()
    {
        try
        {
            IPHostEntry ipHostInfo = Dns.GetHostEntry(IPAddress.Parse("127.0.0.1"));
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
            client = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
            client.BeginConnect(remoteEP,
                new AsyncCallback(ConnectCallback), client);
            connectDone.WaitOne();
            while (true)
            {
                command = Console.ReadLine();
                if (command == "exit")
                {
                    Console.WriteLine("Terminating...");
                    client.Shutdown(SocketShutdown.Both);
                    client.Close();
                    Environment.Exit(0);
                }
                else
                {
                    Send(client, command + "<EOF>");
                    sendDone.WaitOne();
                    Receive(client);
                    receiveDone.WaitOne();
                    Console.WriteLine("Response received : {0}", ProcessResponse(response));
                    client.Shutdown(SocketShutdown.Both);
                    client.Close();
                }
                //Console.CancelKeyPress += (sender, e) =>
                //{
                //    Console.WriteLine("Terminating...");
                //    client.Shutdown(SocketShutdown.Both);
                //    client.Close();
                //    Environment.Exit(0);
                //};
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    static public string ProcessResponse(string pkt)
    {
        string response = null;
        response = pkt.Replace("<EOF>","");
        return response;
    }
    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndConnect(ar);
            Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());
            connectDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Receive(Socket client)
    {
        try
        {
            StateObject state = new StateObject();
            state.skt = client;
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.skt;
            int bytesRead = client.EndReceive(ar);
            if (bytesRead > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Send(Socket client, String data)
    {
        byte[] byteData = Encoding.ASCII.GetBytes(data);
        client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
    }

    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;
            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);
            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    public static int Main(String[] args)
    {
        StartClient();
        return 0;
    }

服务器:

public class Program
{
    public class StateObject
    {
        public Socket skt = null;
        public const int buffersize = 1024;
        public byte[] buffer = new byte[buffersize];
        public StringBuilder sb = new StringBuilder();
    }
    public class AsynchronousSocketListener
    {
        public static ManualResetEvent allDone = new ManualResetEvent(false);
        public AsynchronousSocketListener() { }
        public static Socket handler;
        public static void StartListening()
        {
            byte[] bytes = new Byte[1024];
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);

            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(100);
                while (true)
                {
                    allDone.Reset();
                    Console.WriteLine("Waiting for a connection...");
                    listener.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);
                    allDone.WaitOne();
                }

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

            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();
        }
        public static void AcceptCallback(IAsyncResult ar)
        {
            allDone.Set();
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);
            StateObject state = new StateObject();
            state.skt = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.buffersize, 0, new AsyncCallback(ReadCallback), state);
        }
        public static void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.skt;
            int bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(
                state.buffer, 0, bytesRead));
                content = state.sb.ToString();
                if (content.IndexOf("<EOF>") > -1)
                {
                    Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, ProcessResponse(content));
                    Send(handler, content);
                }
                else
                {
                    handler.BeginReceive(state.buffer, 0, StateObject.buffersize, 0,
                    new AsyncCallback(ReadCallback), state);
                }
            }
        }
        private static void Send(Socket handler, String data)
        {
            byte[] byteData = Encoding.ASCII.GetBytes(data);
            handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
        }
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                handler = (Socket)ar.AsyncState;
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to client.", bytesSent);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        static public string ProcessResponse(String pkt)
        {
            string response = null;
            response = pkt.Replace("<EOF>", "");
            return response;
        }
    }
    public static void Main(string[] args)
    {
        AsynchronousSocketListener.StartListening();
    }
}

1 个答案:

答案 0 :(得分:1)

客户端接收回调:

private static void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.skt;
        int bytesRead = client.EndReceive(ar);
        if (bytesRead > 0)
        {
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            if (state.sb.Length > 1)
            {
                response = state.sb.ToString();
            }
            receiveDone.Set();
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

除非显式关闭套接字(或连接中存在某种其他错误),否则不会下拉到else块。因此,receiveDone永远不会被设置,并且您的主循环只是等待“响应”。

如果您想在处理“完整消息”时处理它,请在将当前字符串附加到缓冲区后检查<EOF>值,如下所示:

            if (bytesRead > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                // it's not a "response" unless it's terminated with "<EOF>" right?
                response = state.sb.ToString();
                if (response.IndexOf("<EOF>") != -1)
                {
                    state.sb.Clear();
                    receiveDone.Set();
                }
                else
                {
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(ReceiveCallback), state);
                }
            }
            else
            {
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString(); // this is a partial response, not terminated with "<EOF>"
                }
                receiveDone.Set();
            }

请注意,正在使用的响应机制非常有限,因为同时进入的多条消息都会失败,如:Hello<EOF> World!<EOF>它会将这两条消息视为一条长消息。 (我意识到你的例子只发送一条“消息”。)

除了“内容”消息之外,您几乎肯定必须在任何发送“控制”消息的真实应用程序中处理该场景。要处理你使用IndexOf()查找<EOF>并提取文本到那一点并处理“完成消息”。之后,只要仍然找到<EOF>来处理其他待处理消息,您就会继续循环。您还必须从StringBuilder中删除那些已处理的完整消息,使<EOF>之后的任何剩余值保留在原位,以便当部分消息进入时,新数据可以附加到现有数据。这是因为您的数据在发送时也可以被分割,导致收到多个“数据块”的数据,即使它在发送时逻辑上是一个“完整的消息”。因此,使用Complete Message<EOF>的一次发送可能会导致一个或多个收到,例如Comp后跟lete Message<EOF>。您的代码必须能够处理TCP通信的这些现实......