TCP服务器&客户没有收到对方的信息

时间:2016-11-30 10:50:04

标签: c# sockets tcp transmission

我对TCP的所有事情都很陌生,我无法在这里找到问题所在。你们中的一些人可能会非常明显。当我运行代码时,我在服务器端运行启动过程,它显示“等待连接”,然后我启动客户端,后面的显示器连接到',I重新启动服务器端的启动过程,并显示“已连接到客户端”。然后,在双方,当我调用方法SendThroughTCPSocket("无论字符串")时,我可以看到它被发送但是另一方没有检测到任何东西?
我能做错什么? 我怎么能让他们两个经常互相倾听?

服务器端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Server
{
// State object for reading client data asynchronously
public class StateObject
{

    #region instance variables

    // Client  socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 1024;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
    // Received data string.
    public StringBuilder sb = new StringBuilder();

    #endregion

}

public class AsynchronousSocketListener
{

    public enum TransmissionSate
    {
        Waiting,
        Receiving,
        Received,
        Sending,
        Sent,
        Off
    }


    #region class variables

    // Thread signal.
    public static ManualResetEvent allDone = new ManualResetEvent(false);

    public static IPHostEntry ipHostInfo;
    public static IPAddress ipAddress;
    public static IPEndPoint localEndPoint;

    public static Socket listener;
    public static Socket handler;


    //flags
    public static TransmissionSate currentState = TransmissionSate.Off;

    #endregion

    #region constructor

    public AsynchronousSocketListener()
    {
    }

    #endregion

    #region Start Listening

    //Start Listening for Client
    public static void StartListening()
    {
        // Data buffer for incoming data.
        byte[] bytes = new Byte[1024];

        // Establish the local endpoint for the socket.
        // The DNS name of the computer
        ipHostInfo = Dns.Resolve(Dns.GetHostName());
        ipAddress = ipHostInfo.AddressList[0];
        localEndPoint = new IPEndPoint(ipAddress, 11000);

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

        // Bind the socket to the local endpoint and listen for incoming connections.
        try
        {
            listener.Bind(localEndPoint);
            listener.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...");
                listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    listener);

                //flag
                currentState = TransmissionSate.Waiting;

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

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


        Console.WriteLine("\nConnected to the client.");
        //Console.Read();

    }

    #endregion

    #region Receive Methods

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

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

        //flag
        currentState = TransmissionSate.Receiving;

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

    //Read and handle the information
    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;
        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)
            {

                //flag 
                currentState = TransmissionSate.Received;

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

                //reference
                Data.lastResponse = content;

                //react
                Console.WriteLine("Server just received a request");
                switch (content)
                {
                    case "DataRequest":
                        Console.WriteLine("Client is trying to get the preset data");
                        SendThroughTCPSocket(Data.xmlToSend + Data.endOfFile);
                        break;

                    default:
                        Console.WriteLine("Unknown request from Client");
                        break;
                }

            }
            else
            {
                // Not all data received. Get more.
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
            }
        }
    }

    #endregion

    #region Send Methods

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

        //flag
        currentState = TransmissionSate.Sending;

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

    //Sending data and closing 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);

            //flag
            currentState = TransmissionSate.Sent;

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

    #endregion

    #region SendThroughTCPSocket

    public static void SendThroughTCPSocket(String data)
    {
        try
        {
            // Send data to the client
            Send(handler, data);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

    }

    #endregion

    #region Stop Server

    //Close Sever  
    public static void StopServer()
    {
        try
        {
            // Release the socket.
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();

            //flag
            currentState = TransmissionSate.Off;

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

    #endregion

}
}

客户端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Client
{
// State object for receiving data from remote device.
public class StateObject
{


    #region instance variables

    // 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();

    #endregion

}

public class AsynchronousClient
{

    public enum TransmissionSate
    {
        Waiting,
        Receiving,
        Received,
        Sending,
        Sent,
        Off
    }


    #region instance variables

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

    #endregion

    #region class variables

    // 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;

    public static IPHostEntry ipHostInfo;
    public static IPAddress ipAddress;
    public static IPEndPoint remoteEP;

    public static Socket client;

    //flags
    public static TransmissionSate currentState = TransmissionSate.Off;
    public static bool isConnected = false;

    #endregion

    #region Start Client

    //Start Client and use it 
    public static void StartClient()
    {
        // Connect to a remote device.
        try
        {
            //flag 
            isConnected = false;

            // Establish the remote endpoint for the socket.
            // The name of the host
            // remote device is the current device
            ipHostInfo = Dns.Resolve(Dns.GetHostName());
            ipAddress = ipHostInfo.AddressList[0];
            remoteEP = new IPEndPoint(ipAddress, port);

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

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

            //flag
            currentState = TransmissionSate.Waiting;

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

    #endregion

    #region Stop Client

    //Close Client 
    public static void StopClient()
    {
        try
        {
            // Release the socket.
            client.Shutdown(SocketShutdown.Both);
            client.Close();

            //flag
            currentState = TransmissionSate.Off;
            isConnected = false;

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

    #endregion

    #region Connect

    //callback for connection
    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());

            // Signal that the connection has been made.
            connectDone.Set();

            //flag
            isConnected = true;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Receive

    //Receive data
    private static void Receive(Socket client)
    {
        try
        {
            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = client;

            //flag
            currentState = TransmissionSate.Receiving;

            // Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    //callback Receive
    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));

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // All the data has arrived; put it in response.
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                // Signal that all bytes have been received.
                receiveDone.Set();

                //flag 
                currentState = TransmissionSate.Received;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Send

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

        //flag
        currentState = TransmissionSate.Sending;

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

    //Callback send
    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);

            // Signal that all bytes have been sent.
            sendDone.Set();

            //flag
            currentState = TransmissionSate.Sent;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region SendThroughTCPSocket

    public static string SendThroughTCPSocket(String data)
    {
        try
        {
            // Send data to the remote device.
            Send(client, data);
            sendDone.WaitOne();

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

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

            return response;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return "<No response>";
        }

    }

    #endregion

}
}

1 个答案:

答案 0 :(得分:1)

您需要在套接字上实现协议。在您的服务器中,您正在使用&#34;&#34;确定邮件已经结束,只有在您收到邮件后才打印出来。但是,我可以在客户端看到无处可见的地方。理想情况下,您希望拥有消息令牌的开头和消息令牌的结尾,以便您可以通过套接字发送多条消息。 将您的客户端发送方法更改为

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

        //flag
        currentState = TransmissionSate.Sending;

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

这应该可行,但我建议实施一个带有开始和结束令牌的协议。

在客户端的receivecallback中,您的代码永远不会检查任何类型的协议,只是尝试继续接收数据:

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

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }

在某个阶段,您的程序必须检查数据以查看是否存在某种类型的结束令牌。 请尝试将其更改为以下内容:

                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));
                var endPos = state.sb.ToString().IndexOf("<EOF>");
                if (endPos > -1) //we have a complete message. huzzah!
                {
                    response = state.sb.ToString().Substring(0, endPos);
                    // Signal that all bytes have been received.
                    receiveDone.Set();
                    //flag 
                    currentState = TransmissionSate.Received;
                }
                else
                // Get the rest of the data.
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }

我必须重申:如果你打算使用原始套接字,你需要设计一个协议:一种识别谨慎消息开始和结束的方法。