#java #multithreading #sockets #tcp
#java #многопоточность #сокеты #tcp
Вопрос:
Я пытаюсь создать программу одноранговой передачи файлов, но у меня возникли некоторые проблемы с первоначальным обменом сообщениями «вот какие фрагменты у меня есть!» между вновь прибывающими одноранговыми узлами и теми, кто уже был там.
По сути, как только вновь прибывший одноранговый узел (которого мы будем называть B) устанавливает TCP-соединение (всегда успешно) с тем, который уже был там (которого мы будем называть A), он отправляет массив, представляющий, какие части файла у него есть. В большинстве случаев это успешно, но для того, чтобы 3-й, 4-й или 5-й одноранговый узел присоединился к 6-одноранговому сеансу, A отправит свой массив, но B иногда его не получит. Обычно один или два массива пропадают без вести. Тем не менее, они продолжают обмениваться фрагментами и в остальном прекрасно общаются — просто теперь B никогда не узнает, есть ли у A фрагменты, которые он получил до присоединения B.
Что касается инфраструктуры, каждое соединение между одноранговыми узлами находится в своем собственном потоке. Только этот поток когда-либо считывает или записывает в сокет, соединяющий их. В любой момент времени между всеми потоками происходит много обмена данными, но внутри каждого потока он всегда поступает в один сокет и из него; хотя есть «thread wrangler», который выполняет некоторое дополнительное управление протоколом (хотя нет чтения или записи в сокет), ничего из этогопротокол действительно работает, когда одноранговый узел просто подключается.
Есть ли какая-либо причина, по которой это может быть, или способы это исправить? Соответствующий код ниже. Следует отметить, что это буквально ЕДИНСТВЕННАЯ часть связи, которая пропала без вести. Все остальное учтено.
Сразу после установления соединения:
locked = true; //a volatile boolean
byte[] pieces = this.makePacket(piecesArray)
this.out.write(pieces);
locked = false
‘locked’, если true, не позволит одноранговому узлу вносить какие-либо обновления в свой массив, пока он снова не станет false. Это было сделано для решения проблемы с тем, что отправляемый массив не был полностью обновлен. ‘locked’ оценивается только на предмет достоверности (для перехода в цикл while) при получении сообщения об обновлении фрагмента.
В основном цикле приема:
byte [] sizeField = new byte[4];
this.in.read(sizeField);
int size = ByteBuffer.wrap(sizeField).getInt();
byte[] packet = new byte[size];
int bytesRead = this.in.read(packet);
while (bytesRead < size)
{
bytesRead = bytesRead this.in.read(packet, bytesRead, size-bytesRead);
}
if(packet.getMessage() == "Pieces")
{
//store em -- if the piece array exchange message doesn't arrive, the code in here never runs
}
Комментарии:
1. Я не уверен, что понимаю: новый пользователь (B) всегда отправляет список своих частей первому пользователю (A), даже если уже есть более одного пользователя?
2. При первом входе в приложение пользователь получит списки элементов всех других пользователей, запущенных в данный момент. A представляет любого ранее существовавшего пользователя, в то время как B представляет самого нового. После запуска приложения B свяжется и соединится со всеми, кто был до него, и обменяется с ними списками элементов, а затем будет ждать (в другом потоке) приема новых входящих подключений.
3. Можете ли вы использовать Wireshark, чтобы узнать, действительно ли данные поступают в провод? Тогда вы знаете, какой конец терпит неудачу.