Страницы

Поиск по вопросам

понедельник, 15 октября 2018 г.

Многопоточный прием данных

Есть СМТП-сервис. Он слушает 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) '
' && currByte[0] == (byte) '
')) { 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; } }


Ответ

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);

Комментариев нет:

Отправить комментарий