Я пытаюсь создать TCP-сервер & Клиент, который будет иметь постоянное соединение, чтобы сервер и клиент в любой момент времени могли уведомлять друг друга о некоторых «событиях» (так нажмите вместо опроса).C# TcpClient, читающий несколько сообщений по постоянному соединению
У меня почти все работает, клиенты могут подключаться, соединение остается открытым, а клиент и сервер могут писать &, прочитанные из потока tcp.
Проблема с чтением, я определил границу сообщения, сначала отправив 8 байтов, которые содержат длину сообщения. После того, как я его получил, сообщения длины x читаются и возникает событие.
Это все работает нормально, но после того, как сообщение было прочитано, я хочу, чтобы «ожидание stream.ReadAsync» ожидало новые входящие данные, но он продолжает циклизацию (и возвращает 0 данных) вместо ожидания, вызвав 100% -ное использование процессора.
Есть ли способ сказать «Сбросить» поток, чтобы он снова начал ждать, как это было первоначально.
Это код для моего tcpclient (используется для отправки и получения), вы можете перейти к методу RunListener, я не думаю, что остальное имеет значение.
public class SSLTcpClient : IDisposable {
/**
* Public fields
*/
public SslStream SslStream { get; private set; }
/**
* Events
*/
public ConnectionHandler connected;
public ConnectionHandler disconnected;
public DataTransfer dataReceived;
/**
* Constructors
*/
public SSLTcpClient() { }
public SSLTcpClient(TcpClient pClient, X509Certificate2 pCert) {
SslStream = new SslStream(
pClient.GetStream(),
false,
new RemoteCertificateValidationCallback(
delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
return true;
}
),
new LocalCertificateSelectionCallback(
delegate(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) {
return new X509Certificate2(pCert);
}
)
);
try {
SslStream.AuthenticateAsServer(pCert, true, SslProtocols.Tls, true);
} catch (AuthenticationException) {
pClient.Close();
return;
}
Thread objThread = new Thread(new ThreadStart(RunListener));
objThread.Start();
if (connected != null) {
connected(this);
}
}
/**
* Connect the TcpClient
*/
public bool ConnectAsync(IPAddress pIP, int pPort, string pX509CertificatePath, string pX509CertificatePassword) {
TcpClient objClient = new TcpClient();
try {
if(!objClient.ConnectAsync(pIP, pPort).Wait(1000)) {
throw new Exception("Connect failed");
};
} catch (Exception) {
return false;
}
X509Certificate2 clientCertificate;
X509Certificate2Collection clientCertificatecollection = new X509Certificate2Collection();
try {
clientCertificate = new X509Certificate2(pX509CertificatePath, pX509CertificatePassword);
clientCertificatecollection.Add(clientCertificate);
} catch(CryptographicException) {
objClient.Close();
return false;
}
SslStream = new SslStream(
objClient.GetStream(),
false,
new RemoteCertificateValidationCallback(
delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
return true;
}
),
new LocalCertificateSelectionCallback(
delegate(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) {
var cert = new X509Certificate2(pX509CertificatePath, pX509CertificatePassword);
return cert;
}
)
);
try {
SslStream.AuthenticateAsClient(pIP.ToString(), clientCertificatecollection, SslProtocols.Tls, false);
} catch (AuthenticationException) {
objClient.Close();
return false;
}
Thread objThread = new Thread(new ThreadStart(RunListener));
objThread.Start();
if (connected != null) {
connected(this);
}
return true;
}
/**
* Reading
*/
private async void RunListener() {
try {
while (true) {
byte[] bytes = new byte[8];
await SslStream.ReadAsync(bytes, 0, (int)bytes.Length);
int bufLenght = BitConverter.ToInt32(bytes, 0);
if (bufLenght > 0) {
byte[] buffer = new byte[bufLenght];
await SslStream.ReadAsync(buffer, 0, bufLenght);
if (dataReceived != null) {
dataReceived(this, buffer);
}
}
}
} catch (Exception) {
Dispose();
}
}
/**
* Writing
*/
public bool Send(byte[] pData) {
try {
byte[] lenght = BitConverter.GetBytes(pData.Length);
Array.Resize(ref lenght, 8);
SslStream.Write(lenght);
if (!SslStream.WriteAsync(pData, 0, pData.Length).Wait(1000)) {
throw new Exception("Send timed out");
}
} catch (Exception) {
Dispose();
return false;
}
return true;
}
public bool Send(string pData) {
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(pData);
return Send(bytes);
}
/**
* Shutdown
*/
public void Dispose() {
SslStream.Close();
if (disconnected != null) {
disconnected(this);
}
}
}
На первый взгляд вы называете 'ReadAsync', не глядя на' int', он возвращается. Это всегда ошибка кодирования. Перейдите к [документации] (https://msdn.microsoft.com/en-us/library/hh137813 (v = vs.110) .aspx) * «Задача, представляющая операцию асинхронного чтения. Значение TResult параметр содержит общее количество байтов, считанных в буфере.** Значение результата может быть меньше количества запрошенных байтов **, если количество доступных в настоящий момент байтов меньше запрошенного числа или оно может быть 0 (ноль), если конец потока достигнут. "* –
Я чувствую себя таким глупым сейчас, я закончил поток, мое тестовое приложение, которое я сделал, вышло после отправки 1 сообщения. По крайней мере, это было простое исправление, спасибо за указание на ошибку. – Crazy