在Xamarin中更改活动后,TcpClient Singleton不会发送/接收数据,Android应用程序

0ve6wy6x  于 2022-12-20  发布在  Android
关注(0)|答案(1)|浏览(135)

我正在开发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;
                }
            }
        }

当应用程序在第一个活动中时,通信没有问题,但当我转到第二个活动时,客户端既不能发送也不能接收数据,虽然应用程序正确地将数据上载到流中,但它们没有发送,我也没有收到任何错误信息。
对于服务器来说,它是最简单的多线程程序,服务器使用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>();
                }
            }
        }

有人知道出了什么问题吗?

anauzrmj

anauzrmj1#

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

相关问题