Данные Java Out Of Band (называемые "срочные данные")
Вот некоторый элементарный код, пытающийся использовать данные OOB (Urgent). Моя проблема заключается в том, что серверная часть не ведет себя одинаково, если клиент находится в C или в Java. Осторожно, вы можете подумать, что что-то сложно на обеих клиентских сторонах, но если я использую сервер C (чтобы получить более точное управление OOB), то оба клиента ведут себя одинаково независимо от того, какой у меня серверный контроль OOB.
Сначала серверная (Java) часть:
Socket s = ss.accept();
s.shutdownOutput();
s.setOOBInline(true);
InputStream is = s.getInputStream();
for (;;) {
byte []d = new byte[3];
int l = is.read(d);
if (l==-1) break;
for (int i=0; i<l; i++) System.out.print((char)d[i]);
System.out.println();
Thread.sleep(2000);
}
Затем клиентская (Java) часть:
Socket s = new Socket("localhost",61234);
s.shutdownInput();
OutputStream os = s.getOutputStream();
byte []n = new byte[10];
for (int i=0; i<n.length; i++) n[i] = (byte)('A'+i);
byte m = (byte)('0');
os.write(n);
System.out.println("normal sent");
s.sendUrgentData(m);
System.out.println("OOB sent");
os.write('Z');
System.out.println("normal sent");
и затем часть альтернативного клиента (C):
s = socket(PF_INET,SOCK_STREAM,0);
bzero(&a,sizeof(a));
a.sin_family = AF_INET;
a.sin_port = htons(61234);
a.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(s,(struct sockaddr *)&a,sizeof(a));
shutdown(s,SHUT_RD);
char m = '0';
char *n = "ABCDEFGHIJ";
printf("normal sent %d\n",write(s,n,strlen(n)));
printf("OOB sent %d\n",send(s,&m,1,MSG_OOB));
printf("normal sent %d\n",write(s,"Z",1));
Теперь вот что я получаю (сначала клиент C, затем клиент Java):
Accepting connection
ABC
DEF
GHI
J
Z
Accepting connection
ABC
DEF
GHI
J
0Z
Кажется, что Java-сервер не может видеть данные OOB, отправленные со стороны C-клиента. Почему 0
кажется, был потерян? Это не так, потому что сервер, по крайней мере, обнаружил границу OOB в потоке.
2 ответа
Внешние данные не поддерживаются одинаково во всех реализациях сокетов. Это так просто.
Совет Microsoft здесь:
В настоящее время существует два противоречивых толкования RFC 793 (где вводится эта концепция).
Реализация данных OOB в Berkeley Software Distribution (BSD) не соответствует требованиям к хосту, указанным в RFC 1122.
В частности, указатель срочности TCP в BSD указывает на байт после байта срочных данных, а RFC-совместимый указатель срочности TCP указывает на байт срочных данных. В результате, если приложение отправляет срочные данные из BSD-совместимой реализации в реализацию, совместимую с RFC 1122, получатель считывает неправильный байт срочных данных (он считывает байт, расположенный после правильного байта в потоке данных, как срочные данные). байт).
Чтобы свести к минимуму проблемы совместимости, разработчикам приложений рекомендуется не использовать данные OOB, если только это не требуется для взаимодействия с существующей службой. Поставщикам Windows Sockets настоятельно рекомендуется документировать семантику OOB (BSD или RFC 1122), которую реализует их продукт.
Если вы пишете новый протокол и вам нужны внеполосные данные, я бы посоветовал вам использовать отдельное соединение для срочных данных или мультиплексировать его на прикладном уровне.
Поэтому мой совет не использовать данные OOB, если у вас есть выбор.
Хорошо, похоже, это связано с реализацией JVM. Я сделал разные тесты, на разных ОС и JVM.
Все правильно на разных Linux с JDK 1.6 (Java 7 не тестировалась).
Но что-то не так с моим Mountain Lion, он ведет себя по-разному в зависимости от версий Java. Кажется, это ошибка JVM, связанная с реализацией Apple.