Я пишу приложение, которое потребуется, чтобы сделать сотни соединений сокетов через TCP для чтения/записи данных.
Для этого вам не нужны «высокопроизводительные сокеты». Код намного проще с сокетами с нормальной производительностью.
Для начала не используйте пользовательские ожидания из указанной вами ссылки. Они отлично подходят для некоторых людей (и полностью «надежны»), но они вам не нужны, и ваш код будет проще без них.
- Существует ничего плохого с вышеизложенным, и она может быть оптимизирована?
Да. Вы не должны смешивать блокировку (Connect
) и асинхронный (ReadAsync
) код. Я бы рекомендовал что-то вроде этого:
foreach (var ip in listofIps)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), 4001);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
await client.ConnectTaskAsync(remoteEP);
...
}
Где ConnectTaskAsync
является standard TAP-over-APM wrapper:
public static Task ConnectTaskAsync(this Socket socket, EndPoint endpoint)
{
return TaskFactory.FromAsync(socket.BeginConnect, socket.EndConnect, endpoint, null);
}
Как Марк Gravell отметил, этот код (и исходный код) подключаются сокеты по одному за раз. Вы можете использовать Task.WhenAll
, чтобы соединить их все одновременно.
2) Есть ли более эффективный способ сделать это?
Во-первых, вы должны определить оболочку TAP-over-APM ReceiveTaskAsync
, аналогичную описанной выше.При работе с двоичными данными, я также хотел бы иметь метод расширения байтовых массивов для захоронения:
public string DumpHex(this ArraySegment<byte> data)
{
return string.Join(" ", data.Select(b => b.ToString("X2")));
}
Тогда вы можете иметь такой код:
while (true)
{
int bytesRead = await socket.ReceiveTaskAsync(buffer);
if (bytesRead == 0) break;
var data = new ArraySegment<byte>(buffer, 0, bytesRead);
AppendLog("RX: " + data.HexDump());
...
}
Если вы много бинарных манипуляций , вы можете найти мой ArraySegments library полезным.
3) Где и как я должен включать в себя логику, чтобы проверить, все мои данные прибыли в один прочитать
О, это более сложный, чем это. :) Розетки - это поток абстракция, а не сообщение абстракция. Поэтому, если вы хотите определить «сообщения» в своем протоколе, вам нужно указать префикс длины или разделитель байта, чтобы вы могли обнаружить границы сообщений. Затем вам нужно написать код, который будет анализировать ваши сообщения, имея в виду, что блоки данных, считанные из сокета, могут содержать только частичное сообщение (поэтому вам нужно его буферировать), полное сообщение, несколько полных сообщений, а также может завершите частичное сообщение (опять-таки, буферизацию). И вы должны также рассмотреть свой существующий буфер при получении нового блока.
У меня есть TCP/IP .NET Sockets FAQ в моем блоге, что addresses this specifically и имеет некоторые example code, используя мое личное предпочтение по умолчанию для обрамления сообщений (префикс длины в байтах длиной 4 байта).
4) Как включить метод writeasync, чтобы я мог отправлять данные через сокет в середине чтения.
Это один удивительно сложно:
public static Task<int> SendTaskAsync(this Socket socket, byte[] buffer, int offset, int size, SocketFlags flags)
{
return Task<int>.Factory.FromAsync(socket.BeginSend, socket.EndSend, buffer, offset, size, flags, null);
}
public static Task WriteAsync(this Socket socket, byte[] buffer)
{
int bytesSent = 0;
while (bytesSent != buffer.Length)
{
bytesSent += await socket.SendTaskAsync(data, bytesSent, buffer.Length - bytesSent, SocketFlags.None);
}
}
Вы не можете получить много ответов на этот вопрос, поскольку это является чрезмерно широким и спросите вы, такие как «это может быть дополнительно оптимизирована?». Ответы, как правило, громкие да. – MarcF
Я указал области, которые я хотел, чтобы они были оптимизированы. Я не думаю, что этот вопрос настолько широк, насколько вы его озвучиваете. Я не спрашивал: «Можно ли это оптимизировать?» в общем –
@PapyrusBit Но вы задали три или четыре вопроса, которые напрямую не связаны. Вы должны задать только один вопрос одновременно. – svick