There is an SMTP service. He listens to port 25:

SMTP_Listener = new TcpListener(IPAddress.Any, 25); SMTP_Listener.Start(); 

It turns out that when teams of 2 or more clients send him, they “merge” and it turns out like this (example):

  • Client1: command "HELLO 11111"
  • Client2: team "HELLO 22222"
  • Client3: team "HELLO 33333"

I get "HELLO 11" from the first client, from the second one - "LO 22", for the third one - "LO 3333" (for example).

Tell me how to properly separate reading from several clients?

Each client works for me in a separate stream.

Client Receive Code:

 /// <summary> /// Считываем команду клиента /// </summary> /// <returns></returns> 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 <CRLF> 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; } } 
  • one
    (1) The problem is how you relate the connected client to your ReadLine procedure. Do you have a common clientSocket at all? - VladD
  • one
    (2) Very low level code. Would you switch to NetworkStream and use some higher level functions? - VladD
  • @ VladD, yes clientSocket is common. It is not right? Thank. - Leonard Bertone
  • one
    @LeonardBertone clientSocket - static? if this is a class field, is the class instance one for all? - PashaPash
  • 2
    Well then it is clear, you are overwriting the old socket. You must start a new variable each time and give it to the processing thread. - VladD

1 answer 1

 private Socket clientSocket 

you have one common socket instance for all clients.

when a new client connects

 clientSocket = SMTP_Listener.AcceptSocket(); 

you throw away the socket that was open when the previous client connected. As a result, all the threads you have read from this.clientSocket, referring to the socket open to the last connected client.

Those. all that was sent by previous customers, but that did not have time to deduct - goes into nowhere. And everything that the last client sends is tearing up all the reading threads among themselves.

You should transfer the code associated with client processing to a separate class in order to get a separate instance for each client:

 class ClientProcessor() { private Socket clientSocket; public ClientProcessor(Socket clientSocket) { this.clientSocket = clientSocket; } string ReadLine() {....} void StartProcessing(); } 

and create a new instance for each connected client:

 var processor = new ClientProcessor(SMTP_Listener.AcceptSocket()); Thread newClient = new Thread(processor.StartProcessing); 
  • Thanks, I will try - Leonard Bertone
  • Problem solved, thanks !!!!!!! - Leonard Bertone