#c_sharp #многопоточность #smtp
Есть СМТП-сервис. Он слушает 25ый порт: SMTP_Listener = new TcpListener(IPAddress.Any, 25); SMTP_Listener.Start(); Получается, что когда к нему шлют команды 2 и более клиентов, то они "сливаются" и получается такое (пример): Клиент1: команда "HELLO 11111" Клиент2: команда "HELLO 22222" Клиент3: команда "HELLO 33333" Я получаю "HELLO 11" от первого клиента, от второго- "LO 22", для третьего - "LO 3333" (например). Подскажите, как правильно разделить чтение от нескольких клиентов? У меня каждый клиент работает в отдельном потоке. КОД приема сообщений от клиентов: ////// Считываем команду клиента /// ///private string ReadLine() { try { long lastDataTime = DateTime.Now.Ticks; ArrayList lineBuf = new ArrayList(); byte prevByte = 0; while (true) { if (clientSocket == null) l.Write(" !!! clientSocket is NULL"); if (!clientSocket.Connected) l.Write(" !!! сокет не включен!"); if (clientSocket.Available > 0) { // Read next byte byte[] currByte = new byte[1]; int countRecieved = clientSocket.Receive(currByte, 1, SocketFlags.None); // Count must be equal. Eg. some computers won't give byte at first read attempt if (countRecieved == 1) { lineBuf.Add(currByte[0]); // Line found if ((prevByte == (byte) '\r' && currByte[0] == (byte) '\n')) { byte[] retVal = new byte[lineBuf.Count - 2]; // Remove lineBuf.CopyTo(0, retVal, 0, lineBuf.Count - 2); return System.Text.Encoding.Default.GetString(retVal).Trim(); } // Store byte prevByte = currByte[0]; //l.Write("prevByte = " + prevByte); //// Check if maximum length is exceeded //if (lineBuf.Count > maxLen) //{ // throw new Exception( "Maximum line length exceeded"); //} // reset last data time lastDataTime = DateTime.Now.Ticks; //l.Write("lastDataTime = " + lastDataTime); } } else { // l.Write("clientSocket.Available: " + clientSocket.Available.ToString()); // тут всегда 0 //---- Time out stuff -----------------------// if (DateTime.Now.Ticks > lastDataTime + ((long)(60000)) * 10000) { l.Write("ERROR: Read timeout: " + (((long)(60000)) * 10000).ToString()); //clientSocket.Close(); l.Write("Сокет закрыт из-за простоя в " + (((long)(60000)) * 10000).ToString() + " м-сек."); // throw new Exception("Read timeout"); return ""; // ????????????????????????????????????????????????????????????????????? } System.Threading.Thread.Sleep(100); //------------------------------------------// } } } catch (Exception x) { l.Write("EROR ReadLine(): " + x.ToString()); throw new Exception(x.Message); } } UPD: public void Listen() { int iter = 0; try { l.Write("***************START*******************"); l.Write("SMTP server started " + DateTime.Now.ToString()); SMTP_Listener = new TcpListener(IPAddress.Any, port); SMTP_Listener.Start(); while (true) { //тут я определяю что у нас есть клиент clientSocket = SMTP_Listener.AcceptSocket(); _sessionId = clientSocket.GetHashCode().ToString(); _email.sessionId = Convert.ToInt32(_sessionId); l.Write("New session: " + _sessionId); //и в отдельный поток его Thread newClient = new Thread(StartProcessing); l.Write("Создан поток для обработки клиента " + _sessionId); UserSessionController.AddSession( Convert.ToInt32(_sessionId ) ); newClient.Name = _sessionId; newClient.IsBackground = true; // ??? newClient.Start(); } } catch (Exception ex) { l.Write("SMTP Listen Error: " + ex.ToString()); throw; } }
Ответы
Ответ 1
private Socket clientSocket у вас один общий экземпляр сокета для всех клиентов. когда подключается новый клиент clientSocket = SMTP_Listener.AcceptSocket(); вы выбрасываете сокет, который был открыт при подключении предыдущего клиента. В результате все потоки у вас читают из this.clientSocket, ссылающегося на сокет, открытый для последнего подключенного клиента. Т.е. все, что прислали предыдущие клиенты, но что не успели вычитать - уходит вникуда. А все, что присылает последний клиент, рвут между собой все читающие потоки. Вам стоит перенести код, связанный с обработкой клиента, в отдельный класс, чтобы получить отдельный экземпляр на каждого клиента: class ClientProcessor() { private Socket clientSocket; public ClientProcessor(Socket clientSocket) { this.clientSocket = clientSocket; } string ReadLine() {....} void StartProcessing(); } и создавать новый экземпляр для каждого подключившегося клиента: var processor = new ClientProcessor(SMTP_Listener.AcceptSocket()); Thread newClient = new Thread(processor.StartProcessing);
Комментариев нет:
Отправить комментарий