为什么我不能在套接字连接上发送两次数据?

时间:2016-07-28 15:40:59

标签: c# sockets asynchronous

我正在编写一个简单的客户端服务器套接字程序,无法弄清楚为什么我的客户端仅在第一次按下发送按钮时发送。

第二次“nwStream.Write(bytesToSend,0,bytesToSend.Length);”被调用,服务器无法获取数据......

注意:我已经注释掉了从服务器到客户端的回显,因为服务器在回显后关闭了连接。我希望连接保持打开状态。

请帮我发两次数据......

这是C#FORM客户端代码

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    TcpClient client;
    private void Form1_Load(object sender, EventArgs e)
    {
        textBox_IP.Text = "192.168.0.72";
    }

    const int PORT_NO = 11000;
    private void button_Start_Click(object sender, EventArgs e)
    {
        client = new TcpClient(textBox_IP.Text, PORT_NO);
        textBox_MsgToSend.Text = "Started";
    }

    private void button_Send_Click(object sender, EventArgs e)
    {
        string textToSend = textBox_MsgToSend.Text + " " + DateTime.Now.ToString();
        textToSend += "<EOF>";

        NetworkStream nwStream = client.GetStream();
        byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(textToSend);

        //---send the text---
        textBox_Sending.Text = textToSend;
        textBox_Size.Text = bytesToSend.Length.ToString();
        nwStream.Write(bytesToSend, 0, bytesToSend.Length);

       // commented out as the server does not echo anything back
       //---read back the text---
       //            byte[] bytesToRead = new byte[client.ReceiveBufferSize];
       //            int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
       //            textBox_Received.Text = bytesRead.ToString();
    }

    private void button_Close_Click(object sender, EventArgs e)
    {
        client.Close();
        textBox_MsgToSend.Text = "Closed";
    }

}

以下是表单设计器代码:

partial class Form1
{
    // <summary>
    // Required designer variable.
    // </summary>
    private System.ComponentModel.IContainer components = null;

    // <summary>
    // Clean up any resources being used.
    // </summary>
    // <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.button_Start = new System.Windows.Forms.Button();
        this.button_Send = new System.Windows.Forms.Button();
        this.button_Close = new System.Windows.Forms.Button();
        this.textBox_MsgToSend = new System.Windows.Forms.TextBox();
        this.textBox_Received = new System.Windows.Forms.TextBox();
        this.textBox_IP = new System.Windows.Forms.TextBox();
        this.label1 = new System.Windows.Forms.Label();
        this.label2 = new System.Windows.Forms.Label();
        this.textBox_Sending = new System.Windows.Forms.TextBox();
        this.label3 = new System.Windows.Forms.Label();
        this.textBox_Size = new System.Windows.Forms.TextBox();
        this.SuspendLayout();
        // 
        // button_Start
        // 
        this.button_Start.Location = new System.Drawing.Point(30, 28);
        this.button_Start.Name = "button_Start";
        this.button_Start.Size = new System.Drawing.Size(75, 23);
        this.button_Start.TabIndex = 0;
        this.button_Start.Text = "Start";
        this.button_Start.UseVisualStyleBackColor = true;
        this.button_Start.Click += new System.EventHandler(this.button_Start_Click);
        // 
        // button_Send
        // 
        this.button_Send.Location = new System.Drawing.Point(30, 73);
        this.button_Send.Name = "button_Send";
        this.button_Send.Size = new System.Drawing.Size(75, 23);
        this.button_Send.TabIndex = 1;
        this.button_Send.Text = "Send";
        this.button_Send.UseVisualStyleBackColor = true;
        this.button_Send.Click += new System.EventHandler(this.button_Send_Click);
        // 
        // button_Close
        // 
        this.button_Close.Location = new System.Drawing.Point(30, 172);
        this.button_Close.Name = "button_Close";
        this.button_Close.Size = new System.Drawing.Size(75, 23);
        this.button_Close.TabIndex = 2;
        this.button_Close.Text = "Close";
        this.button_Close.UseVisualStyleBackColor = true;
        this.button_Close.Click += new System.EventHandler(this.button_Close_Click);
        // 
        // textBox_MsgToSend
        // 
        this.textBox_MsgToSend.Location = new System.Drawing.Point(120, 73);
        this.textBox_MsgToSend.Name = "textBox_MsgToSend";
        this.textBox_MsgToSend.Size = new System.Drawing.Size(207, 20);
        this.textBox_MsgToSend.TabIndex = 3;
        // 
        // textBox_Received
        // 
        this.textBox_Received.Location = new System.Drawing.Point(120, 174);
        this.textBox_Received.Name = "textBox_Received";
        this.textBox_Received.Size = new System.Drawing.Size(207, 20);
        this.textBox_Received.TabIndex = 4;
        // 
        // textBox_IP
        // 
        this.textBox_IP.Location = new System.Drawing.Point(120, 28);
        this.textBox_IP.Name = "textBox_IP";
        this.textBox_IP.Size = new System.Drawing.Size(128, 20);
        this.textBox_IP.TabIndex = 5;
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(117, 57);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(90, 13);
        this.label1.TabIndex = 7;
        this.label1.Text = "Message to Send";
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(117, 96);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(49, 13);
        this.label2.TabIndex = 9;
        this.label2.Text = "Sending:";
        // 
        // textBox_Sending
        // 
        this.textBox_Sending.Location = new System.Drawing.Point(120, 112);
        this.textBox_Sending.Name = "textBox_Sending";
        this.textBox_Sending.ReadOnly = true;
        this.textBox_Sending.Size = new System.Drawing.Size(207, 20);
        this.textBox_Sending.TabIndex = 8;
        // 
        // label3
        // 
        this.label3.AutoSize = true;
        this.label3.Location = new System.Drawing.Point(330, 96);
        this.label3.Name = "label3";
        this.label3.Size = new System.Drawing.Size(27, 13);
        this.label3.TabIndex = 11;
        this.label3.Text = "Size";
        // 
        // textBox_Size
        // 
        this.textBox_Size.Location = new System.Drawing.Point(333, 112);
        this.textBox_Size.Name = "textBox_Size";
        this.textBox_Size.ReadOnly = true;
        this.textBox_Size.Size = new System.Drawing.Size(65, 20);
        this.textBox_Size.TabIndex = 10;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(447, 262);
        this.Controls.Add(this.label3);
        this.Controls.Add(this.textBox_Size);
        this.Controls.Add(this.label2);
        this.Controls.Add(this.textBox_Sending);
        this.Controls.Add(this.label1);
        this.Controls.Add(this.textBox_IP);
        this.Controls.Add(this.textBox_Received);
        this.Controls.Add(this.textBox_MsgToSend);
        this.Controls.Add(this.button_Close);
        this.Controls.Add(this.button_Send);
        this.Controls.Add(this.button_Start);
        this.Name = "Form1";
        this.Text = "Client";
        this.Load += new System.EventHandler(this.Form1_Load);
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.Button button_Start;
    private System.Windows.Forms.Button button_Send;
    private System.Windows.Forms.Button button_Close;
    private System.Windows.Forms.TextBox textBox_MsgToSend;
    private System.Windows.Forms.TextBox textBox_Received;
    private System.Windows.Forms.TextBox textBox_IP;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Label label2;
    private System.Windows.Forms.TextBox textBox_Sending;
    private System.Windows.Forms.Label label3;
    private System.Windows.Forms.TextBox textBox_Size;
}

现在服务器

服务器是一个控制台应用程序,它有两个类和一个主

// State object for reading client data asynchronously
public class StateObject
{
    // 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();
}

这是服务器代码:

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

    public AsynchronousSocketListener()
    {
    }

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

        IPAddress address = IPAddress.Parse(ip);

        Console.WriteLine("listening on IP " + ip + " Port " + "11000");

        IPEndPoint localEndPoint = new IPEndPoint(address, 11000);

        // Create a TCP/IP socket.
        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);

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

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

        Console.WriteLine("\nPress ENTER to continue...");
        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);

        Console.WriteLine("Connected...");

        // 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)
    {
        Console.WriteLine("ReadCallback");

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

                // I commented this out as when the send completes, the server closes the connection... I want the connection to remain open
                // Echo the data back to the client.
                //Send(handler, content);
            }
            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);

        Console.WriteLine("Echo back to client : " + 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);

            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

这里是主要的:

public static int Main(String[] args)
{
    StartListening( "192.168.0.72" );
    return 0;
}

尝试1:

我在public static void AcceptCallback(IAsyncResult ar)函数中试过这个:

    while(true)
    {
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
    }

ATTEMPT2:

Per SpaceghostAli的回复/代码:不起作用......第二次发送时崩溃

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)
    {
        Console.WriteLine("ReadCallback");

        // 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. Data : {1}", content.Length, content);

            state = new StateObject();
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);

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

尝试3:

根据David所说的另一种尝试,但在功能结束时重置BeginReceive - WORKS!

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)
    {
        Console.WriteLine("ReadCallback");

        // 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. Data : {1}", content.Length, content);

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

    // clear the state object's buffer and queue the next begin receive
    state.sb.Clear();
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}

2 个答案:

答案 0 :(得分:2)

一旦您的服务器读取消息然后将其写入控制台,它就永远不会再次开始阅读。它只是退出&#34; ReadCallback&#34;。服务器的连接保持打开状态,但它将永远不会再读取。

要解决这个问题,你应该开始另一个&#34; BeginReceive&#34;在你写完最后收到的信息之后。

答案 1 :(得分:2)

我赞成大卫的回答,因为我认为这是正确的,所以请将其标记为这样,这只是为了澄清他根据您的更新意味着什么

public static void ReadCallback(IAsyncResult ar)
{
    Console.WriteLine("ReadCallback");

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

            // continue reading
            state = new StateObject();
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);

            // I commented this out as when the send completes, the server closes the connection... I want the connection to remain open
            // Echo the data back to the client.
            //Send(handler, content);
        }
        else
        {
            // Not all data received. Get more
            // start writing at bytesRead in the buffer so you don't lose the partially read data
            handler.BeginReceive(state.buffer, bytesRead, StateObject.BufferSize, 0,
        new AsyncCallback(ReadCallback), state);
        }
    }
}