Я пытаюсь создать TCP-сервер и клиент, который будет иметь постоянное соединение, чтобы сервер и клиент в любой момент времени могли уведомлять друг друга об определенных «событиях» (так что нажмите вместо опроса).
У меня почти все работает, клиенты могут подключаться, соединение остается открытым, а клиент и сервер могут как писать, так и читать из потока tcp.
Проблема с чтением, я определил границу сообщения, сначала отправив 8 байтов, которые содержат длину сообщения. Как только я его получил, сообщения длины x читаются и возникает событие.
Все это работает нормально, но как только сообщение будет прочитано, я хочу, чтобы «ожидание потока.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
. Это всегда ошибка кодирования. Прочтите документацию Задача, представляющая асинхронную операцию чтения. Значение параметра TResult содержит общее количество байтов, считанных в буфер. Результирующее значение может быть меньше запрошенного количества байтов, если количество доступных в настоящее время байтов меньше запрошенного числа, или может быть равно 0 (ноль), если достигнут конец потока. . - person Scott Chamberlain   schedule 14.12.2015