Проблемы с производительностью серверного / клиентского приложения
Привет, чтобы улучшить мое текущее программное обеспечение, я хотел переключить datalogic на серверное приложение, которое имеет более быстрое соединение с базой данных и может кэшировать данные.
До сих пор я писал работающее серверное приложение и клиент, который подключается к этому серверу.
В настоящее время я испытываю проблему производительности на стороне сервера, приводящую к высокой загрузке процессора, и я хотел бы спросить, Может ли кто-нибудь найти эту проблему.
Сервер и клиент должны взаимодействовать асинхронно, так что несколько клиентов могут работать с сервером, и сервер позже создаст очередь, если операции достигнут более высоких уровней.
Ниже вы найдете код, он немного запутан, так как сейчас это всего лишь прототип.
Я уже прочитал несколько статей о CP и переплетениях на этом, и я думаю, что проблема может возникнуть через цикл назад к началу accept.
Почему? -> Потому что, поскольку accept выполняется асинхронно, я ожидаю, что 4 потока застрянут на endAccept, хотя это всего лишь предположение, но кажется, что это по крайней мере один.
Кроме того, если я останавливаю сервер (закрываю прослушивание и все такое), я всегда получаю исключение в серверной части, где находится endAccept.
Буду рад любому совету или намеку на проблему.
Спасибо в афвансе
Что я уже пробовал:
Я написал сервер примерно так:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Security; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using System.Runtime.Serialization; using System.Security.Cryptography.X509Certificates; namespace ImsServer.ImsSockets { public class ServerSocket { private TcpListener _listeningSocket; private readonly IPEndPoint _localEndPoint; private ServerMain _serverMainUi; List<TcpClient> _connectedClients = new List<TcpClient>(500); private byte[] _bufferForMessages = new byte[256]; public ServerSocket(ServerMain InUi) { //Get Settings from Config File _localEndPoint = new IPEndPoint(IPAddress.Any, 12000); _serverMainUi = InUi; StartListening(); } internal void StartListening() { try { _listeningSocket = new TcpListener(_localEndPoint); _listeningSocket.Start(100); StartAccept(); } catch (Exception e) { Console.WriteLine(e); } } internal void StartAccept() { //Create an AsyncCallbackForAccept and go to ProcessAccept on completion AsyncCallback _asyncCallbackForAccept = ProcessAccept; //Begin the Accept _listeningSocket.BeginAcceptTcpClient(_asyncCallbackForAccept, _listeningSocket); } private async void ProcessAccept(IAsyncResult InAcceptAsyncResult) { //Get the Listener from the AsyncResult TcpListener _asyncListener = (TcpListener) InAcceptAsyncResult.AsyncState; //Accept the client connection TcpClient _clientToAccept = _asyncListener.EndAcceptTcpClient(InAcceptAsyncResult); await _serverMainUi.SetServerInformationText(Environment.NewLine + "Client : " + _clientToAccept.Client.LocalEndPoint + " Connected"); _connectedClients.Add(_clientToAccept); //SslStream _clientStream = new SslStream(_clientToAccept.GetStream(), false); NetworkStream _clientStream = _clientToAccept.GetStream(); //_clientStream.AuthenticateAsServer(new X509Certificate(), false, true); _clientStream.ReadTimeout = 5000; _clientStream.WriteTimeout = 5000; int _clientIndex = _connectedClients.FindIndex(Cc => Cc == _clientToAccept); byte[] _serverMessageToClient = Encoding.UTF8.GetBytes("You are connected to IMS-Server : Client No " + _clientIndex); _clientStream.Write(_serverMessageToClient, 0, _serverMessageToClient.Length); await _serverMainUi.SetServerInformationText(Environment.NewLine + "Connected Clients : " + _connectedClients.Count); _clientStream.Flush(); //Loop back to accept other requests StartAccept(); while(!_clientStream.DataAvailable) { } _clientStream.BeginRead(_bufferForMessages, 0, _bufferForMessages.Length, ReceiveClientMessageCallback, _clientToAccept); } private async void ReceiveClientMessageCallback(IAsyncResult InAsyncResult) { //TcpClient _client = _connectedClients.Find(Cc => Cc == (TcpClient)InAsyncResult.AsyncState); TcpClient _client = (TcpClient)InAsyncResult.AsyncState; if (_client.Connected) { NetworkStream _clientStream = _client.GetStream(); byte[] _clientMessage = _bufferForMessages; int _noOfBytes = _clientStream.EndRead(InAsyncResult); string _clientDecodedMessage = ""; _clientDecodedMessage = String.Concat(_clientDecodedMessage, Encoding.UTF8.GetString(_clientMessage, 0, _noOfBytes)); await _serverMainUi.SetServerInformationText(Environment.NewLine + "Client : " + _connectedClients.FindIndex(Cc => Cc == _client) + " wants to " + _clientDecodedMessage); if (_clientDecodedMessage == "Disconnect") { //We accept the disconnect wish and send a bye bye byte[] _disconnectMessage = Encoding.UTF8.GetBytes("Bye"); _clientStream.Write(_disconnectMessage, 0, _disconnectMessage.Length); _connectedClients.Remove(_client); } } else { _client.Close(); } } private void AcceptRequestCompleted(object Sender, SocketAsyncEventArgs InArgs) { //ProcessAccept(InArgs); } public bool ServerSocketStop() { bool _connectionsPending = _listeningSocket.Pending(); while(_connectionsPending) { } _listeningSocket.Stop(); return true; } } }
Клиент делает это:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ServerMiniTester { /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window { private TcpClient _client; private byte[] _serverResponse = new byte[256]; public MainWindow() { InitializeComponent(); } private void BtConnectToServerClick(object sender, RoutedEventArgs e) { _client = new TcpClient(); try { _client.Connect(IPAddress.Parse("10.176.2.8"),12000); while(!_client.Connected) { } //SslStream _clientStream = new SslStream(_client.GetStream(), false, ValidateServerCertificate, null); NetworkStream _clientStream = _client.GetStream(); //while(!_clientStream.CanRead) { } //_clientStream.AuthenticateAsClient("10.176.2.8"); AsyncCallback _receiveServerMessage = ReceiveServerMessageCallback; _serverResponse = new byte[256]; _clientStream.BeginRead(_serverResponse, 0, _serverResponse.Length, _receiveServerMessage, _client); } catch (Exception exception) { MessageBox.Show(exception.Message); } } private void BtDisconnectServerClick(object Sender, RoutedEventArgs E) { try { NetworkStream _clientStream = _client.GetStream(); byte[] _disconnectMessage = Encoding.UTF8.GetBytes("Disconnect"); _clientStream.Write(_disconnectMessage, 0, _disconnectMessage.Length); while(!_clientStream.DataAvailable) { Thread.Sleep(50);} AsyncCallback _receiveServerMessage = ReceiveServerMessageCallback; _serverResponse = new byte[256]; _clientStream.BeginRead(_serverResponse, 0, _serverResponse.Length, _receiveServerMessage, _client); } catch (Exception exception) { MessageBox.Show(exception.Message); } } private async void ReceiveServerMessageCallback(IAsyncResult InAsyncResult) { NetworkStream _clientStream = ((TcpClient)InAsyncResult.AsyncState).GetStream(); byte[] _serverMessage = _serverResponse; int _noOfBytes = _clientStream.EndRead(InAsyncResult); string _serverDecodedMessage = ""; _serverDecodedMessage = String.Concat(_serverDecodedMessage, Encoding.UTF8.GetString(_serverMessage, 0, _noOfBytes)); if (_serverDecodedMessage == "Bye") { await SetClientInformationText(Environment.NewLine + "Server response : " + _serverDecodedMessage + Environment.NewLine + "*****Server accepted Disconnect*****"); _client.Close(); _client.Dispose(); await SetClientInformationText(Environment.NewLine + "*****Disconnected from Server*****"); } else { await SetClientInformationText(Environment.NewLine + "Server response : " + _serverDecodedMessage); } } public async Task SetClientInformationText(string InText) { await LbServerResponse.Dispatcher.InvokeAsync(() => LbServerResponse.Text += InText); } private bool ValidateServerCertificate(Object Sender, X509Certificate InCertificate, X509Chain InChain, SslPolicyErrors InSslPolicyErrors) { return true; } } }
RickZeeland
Я всегда борюсь с асинхронным кодом, до такой степени, что я отказался от его использования. Я использую старомодный статический класс TcpReceiver, который использует потоки для каждого клиентского сообщения, и он отлично работает !
HobbyProggy
Поскольку я еще не дошел до этого момента, я попробую асинхронный код. Но если мне нужно будет вернуться к старомодному (ТМ) рабочему коду, я позвоню вам, хорошо?
RickZeeland
Хорошо со мной, было бы лучше, если бы вы получили асинхронный код, работающий, это должно иметь преимущества, особенно когда у вас много клиентов, по-старому это означало бы Новый Поток для каждого клиента !