Есть СМТП-сервис. Он слушает 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" (например).
Подскажите, как правильно разделить чтение от нескольких клиентов?
У меня каждый клиент работает в отдельном потоке.
КОД приема сообщений от клиентов:
///
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
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);
Комментариев нет:
Отправить комментарий