我正在开发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>();
}
}
}
有人知道出了什么问题吗?
1条答案
按热度按时间anauzrmj1#
好吧,我找到解决办法了:最后,在服务器端ClientThread方法中,我应该使用
Array.Clear(bytesFrom, 0, bytesFrom.Length);
而不是bytesFrom = Array.Empty<byte>();
。