繁体   English   中英

TcpClient Singleton 在 Xamarin.Android App 中更改活动后不发送/接收数据

[英]TcpClient Singleton don't sending/receiving data after changing activity in Xamarin.Android App

我正在开发具有多个活动的 Xamarin.Android 应用程序。 我无法在单例中维护 tcp 连接。

public sealed class TcpService
    {
        public TcpClient _tcpClient;
        public NetworkStream _networkStream;
        public string _recievedMessege;
        public Xamarin.Essentials.NetworkAccess networkAccess;
        public bool _isAdmin;
        private TcpService()
        {
            networkAccess = Connectivity.NetworkAccess;
            _tcpClient = new TcpClient();
            _tcpClient.Connect(IPAddress.Parse("10.0.2.2"), 100);
            _networkStream = _tcpClient.GetStream();
            Thread tcpReaderThread = new Thread(ReceiveTcpCommand);
            tcpReaderThread.Start();
        }
        private static TcpService _instance;
        private static readonly object InstanceLock = new object();
        public static TcpService GetInstance()
        {
            if (_instance == null)
            {
                lock (InstanceLock)
                {
                    if (_instance == null)
                        _instance = new TcpService();
                }
            }
            return _instance;
        }

        public void ReceiveTcpCommand()
        {
            byte[] buffer = new byte[0];
            byte[] tempBuffer = new byte[2];
            int packageLength = 0;
            while (true)
            {
                if (_tcpClient.Connected)
                {
                    try
                    {
                        if (packageLength > 0)
                        {
                            _networkStream.Read(buffer, 0, packageLength);
                            packageLength = 0;
                            string recieved = Encoding.ASCII.GetString(buffer);
                            buffer = new byte[1];
                            _recievedMessege = recieved;
                        }
                        else
                        {
                            _networkStream.Read(tempBuffer, 0, tempBuffer.Length);
                            packageLength = BitConverter.ToInt16(tempBuffer);
                            tempBuffer = new byte[2];
                            buffer = new byte[packageLength];
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        tempBuffer = new byte[2];
                        buffer = new byte[1];
                    }
                }
            }
        }

        public void SendTcpCommand(string command)
        {
            if (_tcpClient.Connected && !string.IsNullOrEmpty(command))
            {
                try
                {
                    byte[] tempBytes = Encoding.ASCII.GetBytes(command);
                    byte[] length = BitConverter.GetBytes((Int16)tempBytes.Length);
                    byte[] sendBytes = new byte[length.Length + tempBytes.Length];
                    sendBytes[0] = length[0];
                    sendBytes[1] = length[1];
                    for (int i = 2, j = 0; i < sendBytes.Length; i++)
                    {
                        sendBytes[i] = tempBytes[j++];
                    }
                    _networkStream.Write(sendBytes, 0, sendBytes.Length);
                    _networkStream.Flush();
                }
                catch (Exception ex)
                {

                }
            };
        }



        public void KillTcpConnection()
        {
            SendTcpCommand(string.Format("Disconnect\n"));
            _networkStream.Close();
            _tcpClient.Close();
        }
    }

在 OnCreate 的第一个活动中,我创建了一个单例实例,负责创建与服务器的连接。

TcpService _tcpService;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.LoginLayout);
            // Create your application here

            //...

            _tcpService = TcpService.GetInstance();
            if (_tcpService.networkAccess == NetworkAccess.Internet
                || _tcpService.networkAccess == NetworkAccess.ConstrainedInternet
                || _tcpService.networkAccess == NetworkAccess.Local)
            {
                Thread tcpCallbackThread = new Thread(TcpCallback);
                tcpCallbackThread.Start();
             }
        }

我决定处理传入数据的最佳方法是将其放在单例中的变量中,使用 TcpCallback 方法以线程的形式处理每个活动。

 public void TcpCallback()
        {
            string tempAdminBool=string.Empty;
            while (true)
            {
                if (_tcpService._recievedMessege != null)
                {
                    if (RegexMatcher.IsRegexMatch(_tcpService._recievedMessege, ClientRegexPattern.LoginAccepted))
                    {
                        if(RegexMatcher.RegexMatch(_tcpService._recievedMessege, ClientRegexPattern.LoginAccepted, 1).Equals(1))
                            _tcpService._isAdmin= true;
                        else
                            _tcpService._isAdmin= false;

                        Intent intent = new Intent(this, typeof(MenuActivity));
                        StartActivity(intent);
                    }
                    else if (_tcpService._recievedMessege.Contains("TryToLogin:Denied"))
                    {

                    }
                    else if (RegexMatcher.IsRegexMatch(_tcpService._recievedMessege, TCPServerCommand.InvalidCommand))
                    {
                        Button button = FindViewById<Button>(Resource.Id.button1);
                        button.Text = button.Text.Equals("dupa") ? "0" : "dupa"; 
//dupa is polish word for testing purposes
                    }
                    _tcpService._recievedMessege = null;
                }
            }
        }

当应用在第一个activity时,通信没有问题,但是当我进入第二个activity时,客户端既不能发送也不能接收数据。 虽然应用程序正确地将数据上传到流中,但它们没有发送,我也没有收到任何错误信息。

至于服务器,就是最简单的多线程程序。 服务器使用 TcpListener,当检测到新连接时,它会创建一个新线程来处理与客户端的通信。

public TCPServerController()
        {
            Console.WriteLine("Server is ready...");
            _serverSocket = new TcpListener(_liseningPort);
            _tcpClient = default(TcpClient);
            _serverSocket.Start();
        }

        public void SetupServer()
        {
            int clientCounter = 0;
            while (true)
            {
                if (clientCounter == int.MaxValue)
                    clientCounter = 0;
                clientCounter++;
                _tcpClient = _serverSocket.AcceptTcpClient();
                Console.WriteLine(string.Format("Client No. {0} Connected", clientCounter));
                new HandleClient(_tcpClient, clientCounter);
            }
        }
    }

    public class HandleClient
    {
        TcpClient _client;
        int? _authorizedUserId;
        bool _isUserAdmin = false;
        int _serverClientNumber;
        NetworkStream _networkStream;

        public HandleClient(TcpClient client, int clientNumber)
        {
            _client = client;
            _serverClientNumber = clientNumber;
            Thread clientThread = new Thread(ClientThread);
            clientThread.Start();
        }

        private void ClientThread()
        {
            byte[] bytesFrom = new byte[1024];
            bool connected = true;
            if (_client.Connected)
                _networkStream = _client.GetStream();
            while (connected)
            {
                try
                {
                    if (_client.Connected)
                    {

                        _networkStream.Read(bytesFrom, 0, bytesFrom.Length);
                        string message = Encoding.ASCII.GetString(bytesFrom);
                        _networkStream.Flush();
                        if (!string.IsNullOrEmpty(message))
                            SendResponse(DecodeCommand(message));
                    }
                    else
                    {
                        _authorizedUserId = null;
                        _isUserAdmin = false;
                        connected = false;
                    }
                }
                catch (IOException ex)
                {
                    Console.WriteLine(string.Format("Client No. {0}: The connection was aborted locally!", _serverClientNumber));
                    connected = false;
                    _networkStream.Close();
                    _client.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                finally
                {
                    bytesFrom = Array.Empty<byte>();
                }
            }
        }

有谁知道可能出什么问题了吗?

好的,我找到了解决方案:在服务器端 ClientThread 方法中,最后我应该使用Array.Clear(bytesFrom, 0, bytesFrom.Length); 而不是bytesFrom = Array.Empty<byte>(); .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM