Я создаю сетевую библиотеку на C #, которую я могу использовать в любом приложении, и как часть этой библиотеки у меня есть настройка клиент / сервер TCP.Эта настройка отлично работает практически в любой ситуации;он подключается, отправляет / получает данные и безошибочно отключается при минимальных и средних нагрузках.Однако, когда я отправляю большие объемы данных с клиента на сервер, клиентский сокет работает в течение различного времени (иногда короткого, иногда длительного), а затем просто отказывается отправлять данные некоторое время.В частности, моя скорость передачи данных варьируется от 550-750 Кбит / с до 0 Кбит / с, и снова используется в течение различного периода времени.Затем сокет начнет отправку снова в течение очень короткого времени и снова будет «задушен».Во время регулирования я предполагал, что сокет был отключен, потому что я ничего не мог отправить, но Опрос возвращает, что сокет подключен с использованием следующего кода:
public bool IsConnected(Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
Я только что взял урок по сети в моем колледжепоэтому я начал думать о механизмах контроля перегрузки и управления потоком в TCP, но мне кажется, что ни один из них не вызовет этой проблемы;управление перегрузкой только замедляет скорость передачи данных, и полный буфер на стороне получателя не будет работать почти столько же времени, сколько я получаю со скоростью передачи данных 0 кбит / с.Симптом, по-видимому, указывает либо на некоторый тип сильного удушения данных, либо на массовое отбрасывание пакетов.
Мой вопрос таков: Кто-нибудь имеет представление о том, что может вызвать «удушение» этих данных, из-за отсутствия лучшего термина?Кроме того, возможно ли, что отправляемые мной пакеты идут дальше, чем просто мой маршрутизатор, даже если они адресованы узлу в той же подсети?
Редактировать: Просто так понятно, причина, по которой яЯ пытаюсь решить эту проблему, потому что я хочу отправлять файлы по TCP с максимально возможной скоростью передачи данных.Я понимаю, что UDP также можно использовать, и я также буду принимать решение, используя его, но сначала я хочу, чтобы TCP работал.
Специальная информация:
Я использую блокировку чтения /операции записи, а сервер многопоточный.Клиент также работает в своем собственном потоке.Я тестирую в своей локальной подсети, пропуская все пакеты через мой маршрутизатор, который должен иметь пропускную способность 54 Мбит / с.Размер каждого пакета составляет 8 КБ, и максимум будет отправляться 1000 раз в секунду (поток отправки спит 1 мс), но, очевидно, не достигает этой скорости.Уменьшение размера пакетов для снижения скорости передачи данных приводит к исчезновению регулирования.Windows 7 машин, 1 сервер, 1 клиент.Операция отправки всегда завершается, это ошибка при получении.
Операция отправки приведена ниже:
//get a copy of all the packets currently in the queue
IPacket[] toSend;
lock (packetQueues[c])
{
if (packetQueues[c].Count > SEND_MAX)
{
toSend = packetQueues[c].GetRange(0, SEND_MAX).ToArray();
packetQueues[c].RemoveRange(0, SEND_MAX);
}
else
{
toSend = packetQueues[c].ToArray();
packetQueues[c].RemoveRange(0, toSend.Length);
}
}
if (toSend != null && toSend.Length > 0)
{ //write the packets to the network stream
try
{
writer.Write(toSend.Length);
}
catch (Exception e)
{
Logger.Log(e);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + e, "Error", MessageBoxButtons.OK);
}
for (int i = 0; i < toSend.Length; i++)
{
try
{
toSend[i].Write(writer);
if (onSend != null)
{
object[] args = new object[2];
args[0] = c;
args[1] = toSend[i];
onSend(args);
}
}
catch (Exception e)
{
Logger.Log(e);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + e, "Error", MessageBoxButtons.OK);
}
}
}
И вот код получения:
try
{
//default buffer size of a TcpClient is 8192 bytes, or 2048 characters
if (client.Available > 0)
{
int numPackets = reader.ReadInt32();
for (int i = 0; i < numPackets; i++)
{
readPacket.Clear();
readPacket.Read(reader);
if (owner != null)
{
owner.AcceptPacket(readPacket, c); //application handles null packets itself.
if (onReceive != null)
{
object[] args = new object[2];
args[0] = c;
args[1] = readPacket;
onReceive(args);
}
}
}
timestamps[c] = TimeManager.GetCurrentMilliseconds();
}
else
{
double now = TimeManager.GetCurrentMilliseconds();
if (now - timestamps[c] >= timeToDisconnect)
{ //if timestamp is old enough, check for connection.
connected[c] = IsConnected(client.Client);
if (!connected[c])
{
netStream.Close();
clients[c].Close();
numConnections--;
if (onTimeout != null) onTimeout(c);
}
else
{
timestamps[c] = now;
}
}
}
}
catch (Exception s)
{
Logger.Log(s);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + s, "Error", MessageBoxButtons.OK);
}
Пакет отправки / получения:
public void Write(BinaryWriter w)
{
w.Write(command); //byte
w.Write(data.Type); //short
w.Write(data.Data.Length); //int
w.Write(data.Data); //byte array
w.Flush();
}
/// <summary>
/// Reads a command packet from data off a network stream.
/// </summary>
/// <param name="r">The stream reader.</param>
public void Read(BinaryReader r)
{
command = r.ReadByte();
short dataType = r.ReadInt16();
int dataSize = r.ReadInt32();
byte[] bytes = r.ReadBytes(dataSize);
data = new PortableObject(dataType, bytes);
}
Полный цикл связи с сервером:
public void Communicate(object cl)
{
int c = (int)cl;
timestamps[c] = TimeManager.GetCurrentMilliseconds();
try
{
//Console.Out.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " has started up. c = " + (int)c);
TcpClient client = clients[c];
client.ReceiveTimeout = 100;
NetworkStream netStream = client.GetStream();
BinaryReader reader = new BinaryReader(netStream);
BinaryWriter writer = new BinaryWriter(netStream);
while (client != null && connected[c])
{
#region Receive
try
{
//default buffer size of a TcpClient is 8192 bytes, or 2048 characters
if (client.Available > 0)
{
int numPackets = reader.ReadInt32();
for (int i = 0; i < numPackets; i++)
{
readPacket.Clear();
readPacket.Read(reader);
if (owner != null)
{
owner.AcceptPacket(readPacket, c); //application handles null packets itself.
if (onReceive != null)
{
object[] args = new object[2];
args[0] = c;
args[1] = readPacket;
onReceive(args);
}
}
}
timestamps[c] = TimeManager.GetCurrentMilliseconds();
}
else
{
double now = TimeManager.GetCurrentMilliseconds();
if (now - timestamps[c] >= timeToDisconnect)
{ //if timestamp is old enough, check for connection.
connected[c] = IsConnected(client.Client);
if (!connected[c])
{
netStream.Close();
clients[c].Close();
numConnections--;
if (onTimeout != null) onTimeout(c);
}
else
{
timestamps[c] = now;
}
}
}
}
catch (Exception s)
{
Logger.Log(s);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + s, "Error", MessageBoxButtons.OK);
}
#endregion
Thread.Sleep(threadLatency);
#region Send
//get a copy of all the packets currently in the queue
IPacket[] toSend;
lock (packetQueues[c])
{
if (packetQueues[c].Count > SEND_MAX)
{
toSend = packetQueues[c].GetRange(0, SEND_MAX).ToArray();
packetQueues[c].RemoveRange(0, SEND_MAX);
}
else
{
toSend = packetQueues[c].ToArray();
packetQueues[c].RemoveRange(0, toSend.Length);
}
}
if (toSend != null && toSend.Length > 0)
{ //write the packets to the network stream
try
{
writer.Write(toSend.Length);
}
catch (Exception e)
{
Logger.Log(e);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + e, "Error", MessageBoxButtons.OK);
}
for (int i = 0; i < toSend.Length; i++)
{
try
{
toSend[i].Write(writer);
if (onSend != null)
{
object[] args = new object[2];
args[0] = c;
args[1] = toSend[i];
onSend(args);
}
}
catch (Exception e)
{
Logger.Log(e);
if (showErrorMessages)
MessageBox.Show("Client " + (int)c + ": " + e, "Error", MessageBoxButtons.OK);
}
}
}
#endregion
}
}
catch (ThreadAbortException tae)
{
Logger.Log(tae);
MessageBox.Show("Thread " + (int)cl + " was aborted.", "Error", MessageBoxButtons.OK);
}
}