【问题标题】:C# socket read buffer error with multiple clients connecting to servers多个客户端连接到服务器的 C# 套接字读取缓冲区错误
【发布时间】:2015-02-24 09:24:33
【问题描述】:

我编写了一个 Windows C# 应用程序,它可以创建多达 16 个线程。每个线程为远程设备创建一个套接字。每个线程发送命令来读取设备状态。 (每 300 毫秒)当我创建一个或两个线程来读取状态时就可以了。但是当我创建 10 个线程来读取设备状态时,我会在套接字接收缓冲区中得到错误的数据。

我的socket驱动代码请参考以下:

class SocketClient {

    private IPAddress ipAddress;
    private IPEndPoint remoteEP;
    private Socket mSocket;
    private SocketAsyncEventArgs e = new SocketAsyncEventArgs();
    private System.Timers.Timer timer_connection;
    private static byte[] response = new byte[1024];
    private Boolean waittingConnectDone;
    private Boolean boolConnected;
    public SocketClient() {
    }

    private byte[] acknowledge = null;

    public Boolean Connect(String IP, int Port) {
        Boolean bRet = true;
        ipAddress = IPAddress.Parse(IP);
        remoteEP = new IPEndPoint(ipAddress, Port);
        mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //mSocket.ReceiveTimeout = GlobalVar.ethernet_timeout;
        mSocket.ReceiveTimeout = 500;

        try {
            waittingConnectDone = false;
            e.RemoteEndPoint = remoteEP;
            e.UserToken = mSocket;
            e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
            mSocket.ConnectAsync(e);

            if (timer_connection != null) {
                timer_connection.Dispose();
            } else {
                timer_connection = new System.Timers.Timer();
            }
            timer_connection.Interval = 2000;
            timer_connection.Elapsed += new ElapsedEventHandler(timer_connection_Tick);
            timer_connection.Start();
            while (true) {
                if (waittingConnectDone)
                    break;
                Application.DoEvents();
            }
            bRet = boolConnected;

            //sender.Connect(remoteEP);
        } catch {
            Debug.WriteLine("### Ethernet ### Connection Error!");
            bRet = false;
        }
        return bRet;
    }

    private void e_Completed(object sender, SocketAsyncEventArgs e) {
        boolConnected = true;
        waittingConnectDone = true;
    }

    private void timer_connection_Tick(object sender, EventArgs e) {
        if (!mSocket.Connected) {
            timer_connection.Stop();
            boolConnected = false;
            waittingConnectDone = true;
        }
    }

    public void Disconnect() {
        try {
            mSocket.Shutdown(SocketShutdown.Both);
            mSocket.Close();
        } catch {
        }
    }

每个线程使用以下代码读取设备状态:

    private byte[] acknowledge = null;
    private static byte[] response = new byte[1024];

    public byte[] sendCommand(byte[] Cmp_TxData) {
        try {
            bytesSent = mSocket.Send(Cmp_TxData);
            bytesRec = mSocket.Receive(response);

            acknowledge = new byte[bytesRec];
            Array.Copy(response, 0, acknowledge, 0, bytesRec);
        }
        catch
        {
            acknowledge = null;
        }

        return acknowledge;
    }

缓冲区数据错误如下:

TX --> 00-03-01-F4-00-03-44-14

RX

有时我读到正确的数据,但有时数据都是0!

我的套接字驱动程序有什么问题吗?

非常感谢您的帮助!

【问题讨论】:

  • 'Application.DoEvents();'摆脱那个!!!

标签: c# sockets client


【解决方案1】:

我没有检查所有发布的代码(我怀疑可能会有更多错误,如果你自己尝试多线程很难),但是这一行:

private static byte[] response = new byte[1024];

绝对是您报告的错误类型的来源。这一行声明了一个在所有线程之间共享的缓冲区。

所以如果多个线程这样做:

bytesRec = mSocket.Receive(response);

此响应缓冲区中的数据可以同时修改。

要解决此特定错误,您可以确保使用[ThreadStatic]ThreadLocal 为每个线程创建一个静态缓冲区(例如参见http://reedcopsey.com/2009/11/12/thread-specific-data-becomes-easier-in-net-4-0-via-threadlocalt/)。

【讨论】:

  • 静态... [叹气]。开发人员为什么要这样做?
  • @MartinJames 您愿意解释一下删除Application.DoEvents() 将如何防止OP 报告的错误吗?另外,您是否不同意我的回答,即所述行是报告问题的一个特定来源?
  • 第二个第一 - 不!静态缓冲区显然是错误的,我不明白你是如何得到-1的。我赞成你的回答。 Application.DoEvents() 始终是代码异味,并且 IME 始终可以用健全的消息传递代替。然而,这不是一个答案,所以我把它放在评论中:) A.DE 必须,在任何情况下都不能一次从 16 个线程中调用!!
  • @MartinJames 好的,感谢您的澄清。在这种情况下,您似乎误认为向下箭头表示赞成票;-) 它显示 0 票赞成票,1 票反对票。这就是您的评论令人困惑的原因。
  • oops .. 看起来我搞砸了,然后:( 我修复了它。我无法在不编辑答案的情况下撤销反对票,所以我在最后加了一个点,撤销了投票然后删除了点:)
猜你喜欢
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多