Я использую Protocol Buffers for Swift (последний из CocoaPods) и официальный буфер клиента Java-протокола Google (версия 2.6.0) для передачи сообщений между сервером Java (ServerSocket) и приложением Swift iOS (GCDAsyncSocket).Корректные буферы протокола Сообщения
Большинство сообщений (несколько сотен в секунду, я потоковое аудио как плавающие массивы, между прочим), поток просто отлично. Однако иногда сообщение от клиента к серверу не анализируется. Код Java бросает
com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero)
На обоих концах Посылают 4-байтовый тупоконечник целого числа, представляющее число байт, чтобы следовать, то сообщению сырой Protobuf. На обоих концах я получаю количество последующих байтов, блокируя до тех пор, пока не получу столько байтов, а затем попытаюсь разобрать.
Ошибок в Java-> Swift не наблюдается, только Swift-> Java.
Подавляющее большинство сообщений в порядке. Проблема, по-видимому, возрастает по частоте с количеством обрабатываемых сообщений.
В Java каждый клиент имеет поток, разговаривающий с ним, и поток, прослушивающий его. Поток слушателя вытягивает сообщения с проводов и помещает их в LinkedBlockingQueues для каждого клиента. Говорящий поток вытягивает сообщение с LinkedBlockingQueue для этого клиента, сериализует их и передает их в выходной поток этого клиента.
// Take a messageBuilder, serialize and transmit it
func transmit(messageBuilder: Message_.Builder) {
do {
messageBuilder.src = self.networkID;
let data = try messageBuilder.build().data()
var dataLength = CFSwapInt32HostToBig(UInt32(data.length))
self.socket.writeData(NSData(bytes: &dataLength, length: 4), withTimeout: 1, tag: 0)
self.socket.writeData(data, withTimeout: 1, tag: 0)
} catch let error as NSError {
NSLog("Failed to transmit.")
NSLog(error.localizedDescription)
}
}
Java принимающей стороне:
public void run() {
while (true) {
try {
byte[] lengthField = new byte[4];
try {
ghost.in.readFully(lengthField, 0, 4);
} catch (EOFException e) {
e.printStackTrace();
ghost.shutdown();
return;
}
Integer bytesToRead = ByteBuffer.wrap(lengthField).order(ByteOrder.BIG_ENDIAN).getInt();
byte[] wireMessage = new byte[bytesToRead];
in.readFully(wireMessage, 0, bytesToRead);
HauntMessaging.Message message = HauntMessaging.Message.parseFrom(wireMessage);
// do something with the message
} catch (IOException e) {
e.printStackTrace();
ghost.shutdown();
return;
}
}
}
Любые идеи?
Другая мысль: может ли быть проблема с подписью ByteBuffer, прочитанной на Java, и UInt32 в Swift? Правильно ли я это делаю? – closeparen