【问题标题】:Socket-Programming套接字编程
【发布时间】:2010-10-16 21:46:45
【问题描述】:

好吧,伙计们,我已经绞尽脑汁,无法找到解决方案。 这里的问题是我能够调用一次 begin-receive,但之后我无法找到一种可以一次又一次调用该方法的适当技术。 因此,尽管正在建立连接,但消息只能收到一次,之后就不能再收到了。请帮忙,因为它非常紧急。非常感谢。我在这里写下整个代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.IO;
using.System.Threading;

namespace WindowsApplication1
{
public partial class lanmessenger : Form
{

    Socket client;
    Socket newSock, server, hostSock, remote;


    byte[] receiveBuffer = new byte[1024];
    byte[] sendBuffer = new byte[1024];

    String dataEntered;

    StringBuilder textbox1, receivedData, sb;

    IPEndPoint serverIP, clientIP;

    [DllImport("user32.dll")]
    static extern bool HideCaret(IntPtr hWnd);

    Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    IPAddress localaddress = IPAddress.Parse("127.0.0.1");


    public void Receive()
    {
        if (remote.Connected)
            remote.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), remote);
        else
            return;
    }


    void OnReceivingData(IAsyncResult ar)
    {

        remote = (Socket)ar.AsyncState;

        int recv = remote.EndReceive(ar);

        receivedData = new StringBuilder(Encoding.ASCII.GetString(receiveBuffer, 0, recv));
        //MessageBox.Show(receivedData.ToString(), "received", MessageBoxButtons.OK);

        sb = new StringBuilder(this.textBox1.Text);
        sb.AppendLine(receivedData.ToString());

        if (textBox1.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox1.Text = sb.ToString(); });

        }
        //Receive();     


        return;
    }



    private void Accepted(IAsyncResult ar)
    {
        server = (Socket)ar.AsyncState;
        client = server.EndAccept(ar);
        /*if (client.Connected)
            MessageBox.Show("client connected");*/

        try
        {
            client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), client);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("arguments incorrect in begin-receive call", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException)
        {
            MessageBox.Show("error in accessing socket while receiving", "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while receiving", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("error while receiving", "Error", MessageBoxButtons.OK);
        }

    }

    public void FirstEndPoint()
    {
        newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientIP = new IPEndPoint(localaddress, 5555);

        newSock.Bind(clientIP);
        newSock.Listen(100);

        try
        {
            newSock.BeginAccept(new AsyncCallback(Accepted), newSock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("Error in arguments while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException)
        {
            MessageBox.Show("Error accessing socket while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (InvalidOperationException)
        {
            MessageBox.Show("Invalid operation while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("Exception occurred while using begin-accept", "Error", MessageBoxButtons.OK);
        }
    }

    public void CreateThread()
    {
        Thread FirstThread = new Thread(new ThreadStart(FirstEndPoint));
        FirstThread.Start();
    }

    public lanmessenger()
    {
        InitializeComponent();
        CreateThread();   

    }

    void OnSendingData(IAsyncResult ar)
    {
        Socket socket = (Socket)ar.AsyncState;
        int AmtOfData = socket.EndSend(ar);
        //MessageBox.Show(AmtOfData.ToString());

        return;
    }

    public void SendingData(Socket sock, String data)
    {
        textbox1.AppendLine(this.textBox2.Text);

        if (textBox1.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox1.Text = textbox1.ToString(); });
        }


        if (textBox2.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox2.Text = "\0"; });
        }


        sendBuffer = Encoding.ASCII.GetBytes(data);


        try
        {
            sock.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(OnSendingData), sock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("arguments incorrect in begin-send call", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException ex)
        {
            String str1 = "error in accessing socket while sending" + ex.ErrorCode.ToString();
            MessageBox.Show(str1, "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while sending", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("error while sending", "Error", MessageBoxButtons.OK);
        }
    }

    private void OnClientConnect(IAsyncResult ar)
    {
        Socket sock = (Socket)ar.AsyncState;

        try
        {
            sock.EndConnect(ar);
            if (sock.Connected)
                MessageBox.Show("connected");

        }
        catch (SocketException ex)
        {
            MessageBox.Show("Error in accessing socket while using end-connect" + ex.ErrorCode.ToString(), "Error", MessageBoxButtons.OK);
            return;

        }

        if ((sock.Connected) && (dataEntered != ""))
        {
            SendingData(sock, dataEntered);
        }

    }



    private void button1_Click(object sender, EventArgs e)
    {

        HideCaret(this.textBox1.Handle);

        textbox1 = new StringBuilder(this.textBox1.Text);
        dataEntered = this.textBox2.Text;
        hostSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverIP = new IPEndPoint(localaddress, 5555);


        try
        {
            hostSock.BeginConnect(serverIP, new AsyncCallback(OnClientConnect), hostSock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("Error in arguments while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (SocketException)
        {
            MessageBox.Show("Error in accessing socket while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (InvalidOperationException)
        {
            MessageBox.Show("Invalid operation while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }

        catch (Exception)
        {
            MessageBox.Show("Exception while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }

    }

}

}

【问题讨论】:

    标签: c# .net networking sockets tcp


    【解决方案1】:

    首先,您可能想用一些更合适的标签来标记您的问题。另外 - 由于这是从用于异步 TCP 客户端消息传递的 MSDN 文档中提取的,因此您可能需要再次参考那里的文档。

    (在您本地的 VS 帮助 URL 中:MSDN Asynchronous Client Socket Example

    您没有提到为什么在您的回调方法中启动新的异步接收操作失败 - 您看到什么错误?

    如果您的消息被成功接收并在您的异步回调中处理,您可以从那里再次调用您的 Receive(您已将其注释掉)。请记住,如果您重用您的状态对象(在您的情况下是远程的),您需要清除缓冲区和保留在其中的任何其他对象。

    在您的 Receive 方法中,您应该初始化您的状态对象并再次为新的异步接收操作做好准备。

    另外:我以前使用过的接收回调。其中一些特定于我正在开发的应用程序(例如将消息排入派生的基类中),它相当快速和肮脏,但它可能会有所帮助。

        private void ReceiveCallback(IAsyncResult ar)
        {
            int bytesRead = 0;
    
            try
            {
                // receive finished
                if (ar.IsCompleted)
                {
                    TcpIpState stateObject = (TcpIpState)ar.AsyncState;
                    bytesRead = stateObject.TcpIpSocket.EndReceive(ar, out seSocketError);
                    if (bytesRead > 0)
                    {
                        foreach (ArraySegment<byte> asBuffer in stateObject.Buffer)
                        {
    
                                stateObject.SBuilder.Append(
                                    Encoding.ASCII.GetChars(
                                    asBuffer.Array,
                                    0,
                                    asBuffer.Count));
    
                        }
                        // Let the owner object know of the received message
                        base.EnqueueMessage(new TcpIpMessage(stateObject.SBuilder.ToString()));
    
                        // Start a new receive operation
                        stateObject.SBuilder = new StringBuilder();
                        stateObject.Buffer.Clear();
                        stateObject.Buffer.Add(new ArraySegment<byte>(new byte[_bufferSize]));
                        stateObject.TcpIpSocket.BeginReceive(
                            stateObject.Buffer,
                            SocketFlags.None,
                            new AsyncCallback(ReceiveCallback),
                            stateObject);
                    }
                    else
                    {
                        OnDisconnected(this, new Exception("Bytes returned are 0"));
                        Disconnect();
                    }
                }
            }
            catch (Exception e)
            {
                // Something has gone wrong on a low level portion
                OnDisconnected(this, e);
                Disconnect();
            }
        }
    

    【讨论】:

      【解决方案2】:

      在.NET 中进行异步套接字读取的标准方法是在接收回调结束时重复调用BeginReceive。您似乎对Receive 的必要调用已注释掉。只需取消注释该调用,我希望一切都可以正常工作。我没有对您的代码进行最详细的检查,所以我可能遗漏了一些东西,但这绝对是首先要尝试的事情。也许如果您详细说明您在实施该方法时遇到的确切问题,我们可以为您提供更多帮助。

      作为一个(轻微的)方面,我强烈建议您使用TcpClient 类,如果您在.NET 中进行TCP 通信,显然您就是这样。这简化了很多底层套接字的东西,并且通常使 TCP 通信对程序员更加友好!异步读取“循环”当然也差不多。此外,在 MSDN 和许多其他网站(包括 SO)上有大量关于如何将 TcpClient 类正确用于各种目的的文档和教程/代码 sn-ps(当您想要进行多线程或重用时,它会变得有点棘手TcpClient 对象)。

      【讨论】:

      • 我同意 TcpClient 类。让生活变得更简单(你仍然可以使用 Client 属性访问低级套接字)
      猜你喜欢
      • 2015-07-28
      • 2013-10-09
      • 2022-01-25
      • 2013-11-06
      • 2014-07-22
      • 2011-08-19
      • 1970-01-01
      相关资源
      最近更新 更多