TelNet收到的数据因读取而异

时间:2014-05-30 16:28:30

标签: c# telnet stringbuilder

我有一个小项目,涉及从TelNet客户端接收输入,并根据输入做一些处理并将信息返回给客户。

我现在有大部分工作,一个线程中的监听器和监听器接收的每个客户端然后被赋予它自己的线程。这很好,没有任何错误。当客户端有一些文本输入并在我的代码中接收到这个文本时出现问题,我在按键的基础上通过按键接收的内容是正确的,但是当我将它存储在状态对象中时,我得到了一些奇怪的结果。

这是在侦听器收到新客户端连接时创建的类,它也用于与TelNet客户端之间的通信:

internal class TelNetClient
{
    Socket _socket;

    public TelNetClient(Socket socket)
    {
        var t = new Thread(() => RealStart(socket));            
        t.Start();
    }

    private void RealStart(Socket socket) 
    {
        this.ClientSocket = socket;
    }

    public Socket ClientSocket
    {
        set
        {
            StateObject stateObject;
            DeviceConnection deviceConnection = new DeviceConnection();

            _socket = value;

            stateObject = new StateObject();
            stateObject.WorkSocket = _socket;

            Send(_socket, "Welcome");

            _socket.BeginReceive(stateObject.Buffer, 0, StateObject.BufferSize, 0, 
                new AsyncCallback(ReadCallBack), stateObject);
        }
    }

    internal void ReadCallBack(IAsyncResult asyncResult)
    {
        string content = string.Empty;
        int bytesRead;
        StateObject stateObject;
        DeviceConnection deviceConnection = new DeviceConnection();

        stateObject = (StateObject)asyncResult.AsyncState;

        bytesRead = _socket.EndReceive(asyncResult);

        if (bytesRead > 0)
        {
            ASCIIEncoding ascii = new ASCIIEncoding();
            stateObject.StringBuilder.Append(ascii.GetString(stateObject.Buffer,
                 0, bytesRead));
            content = stateObject.StringBuilder.ToString();

            if (content.EndsWith(deviceConnection.BarcodeTerminator))
            {
                Send(_socket, Environment.NewLine + ">>>>>" + content + "<");
            }
            else
            {
                _socket.BeginReceive(stateObject.Buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallBack), stateObject);
            }
        }
    }

    internal void Send(Socket socket, string data)
    {
        Byte[] byteData;

        byteData = Encoding.ASCII.GetBytes(data);

        socket.BeginSend(byteData, 0, byteData.Length, 0, 
            new AsyncCallback(SendCallBack), socket);
    }

    internal void SendCallBack(IAsyncResult asyncResult)
    {
        int bytesSent;
        Socket socket;

        StateObject stateObject;
        stateObject = new StateObject();
        stateObject.WorkSocket = _socket;

        socket = (Socket)asyncResult.AsyncState;

        bytesSent = socket.EndSend(asyncResult);

        _socket.BeginReceive(stateObject.Buffer, 0, StateObject.BufferSize, 0, 
            new AsyncCallback(ReadCallBack), stateObject);
    }

StateObject对象如下:

internal class StateObject
{
    internal const int BufferSize = 1024;

    internal Socket WorkSocket = null;
    internal Byte[] Buffer = new Byte[BufferSize];
    internal StringBuilder StringBuilder = new StringBuilder();
}

大部分内容可能不是必需的,但我展示了所有内容,以便人们可以看到全貌。

问题在于ReadCallBack方法,因为您可以看到我读取字节数组并将其解码为一个字符串,然后将其附加到StringBuilder类中的StateObject 。解码的值每次都是正确的,但是当调用stateObject.StringBuilder.ToString()时,输出不正确,但它是100%可预测的。这是一个例子:

Key Press Count | Input from TelNet Client | StrinBuilder.ToString() Output      
---------------------------------------------------------------------------
        1       |             A            |                A
        2       |             B            |                B
        3       |             C            |                AC
        4       |             D            |                BD
        5       |             E            |                ACE
        6       |             F            |                BDF

正如您所看到的,最终字符始终是正确的,但前面的字符应该是先前连接在一起的输入,正如您对StringBuilder所期望的那样。在我的各种测试中,这种情况100%发生。它几乎就像StringBuilder丢失了偶数/奇数字符,但是在下一次迭代时再次找到它们!

我尝试将StringBuilder更改为string,但同样的问题也出现了。

有谁知道为什么会发生这种情况以及如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

您正在创建StateObject的两个实例:set_ClientSocket中的一个实例,SendCallback中的另一个实例。作为两个单独的ReadCallback调用的一部分,它们最终都传递到BeginReceive。看起来每个实例都在接收所有其他角色。