|
20.08.2009, 19:09
|
#1
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Lib_binsock: прием/отправка бинарных данных через сокет
Lib_binsock - библиотека для работы с сокетами в трех режимах:
-побайтно(прием/передача)
-прием/передача массивов бинарных данных
-InputStream(Resource)
Обновление. В версии 1.1 добавлена функция flush для немедленной отправки данных
Библиотека содержит следующие функции:
procedure debug_register(idx:integer);
Устанавливает библиотеке идентификатор, который будет передаваться
в обработчик ошибок (о нем ниже) в случае возникновения исключительной ситуации(Exception).
procedure enable_debug(flag:integer);
Включает/отключает режим отладки.
flag = 1 - включить
flag = -1 - выключить
По умолчанию отладка отключена.
Если отладка включена, то в случае возникновения ошибки
вызывается процедура-обработчик, определенная в главной программе, например:
//sender - числовой идентификатор библиотеки, присваиваемый с помощью debug_register //exception - системное сообщение об ошибке //errstr - дополнительное сообщение (указанное при компиляции библиотеки) //code - код ошибки (указанный при компиляции библиотеки) procedure onerror(sender:Integer;exception:string;errstr:string;code:integer); //Имя процедуры, порядок и тип параметров должны быть соблюдены ! begin cmOK:=CreateCommand('OK',CM_OK,1); ShowAlert('Error #'+IntegerToString(code),'Exception: '+exception+chr(10)+chr(13)+'ErrorString: '+errstr, LoadImage('/icon.png'),ALERT_ERROR); delay(20000); ShowForm; end;
Параметр code может иметь следующие значения:
int ERR_OPENERROR = 0; - ошибка открытия сокета
int ERR_CLOSEERROR = 1; - ошибка закрытия сокета
int ERR_AVAILERROR = 2; - ошибка при определении размера буфера
int ERR_READERROR = 3; - ошибка получения данных
int ERR_WRITEERROR = 4; - ошибка отправки данных
Внимание!
В случае, если отладка включена, обработчик должен присутствовать обязательно,
иначе возможен сбой в работе мидлета; если отладка отключена, обработчик объявлять не обязательно.
function open(url:string):integer;
Открывает соединение с адресом url.
Формат url стандартный:
socket://url:port
Возвращает 1 в случае успеха, иначе возвращает -1 и передает в обработчик сообщение об ошибке ERR_OPENERROR.
procedure close;
Закрывает соединение.
В случае неудачи передает в обработчик сообщение об ошибке ERR_CLOSEERROR.
function available:integer;
Возвращает размер доступных для приема данных.
В случае неудачи возвращает -1 и передает в обработчик сообщение об ошибке ERR_AVAILERROR.
function read_byte:integer;
Возвращает следующий байт данных из буфера приема, в случае неудачи возвращает -1 и передает в обработчик сообщение об ошибке ERR_READERROR.
function write_byte(data:integer):integer;
Записывает в буфер передачи байт data.
Возвращает 1 в случае успеха, иначе возвращает -1 и передает ошибку ERR_WRITEERROR.
function get_in_stream:resource;
Возвращает поток resource для подключения.
function write_bin(data:string):integer;
Записывает массив байт data в поток передачи.
Возвращает 1 в случае успеха, иначе возвращает -1 и передает ошибку ERR_WRITEERROR.
function read_bin(len:integer):string;
Возвращает массив байт из входящего потока.
В случае неудачи возвращает null и передает в обработчик сообщение ERR_READERROR.
function rx_count:integer;
Возвращает количество принятых данных.
function tx_count:integer;
Возвращает размер принятых данных.
function flush:integer; c версии 1.1
Инициирует немедленную отправку данных на сервер
Возвращает 1 в случае успеха, иначе возвращает -1 и передает в обработчик сообщение об ошибке
ERR_FLUSHERROR.
Внимание!
---------
Библиотека требует доступа к сети
Проверено на Motorola L9.
Отправку данных проверить не смог, но должно работать.
P.S. Предлагаю всем разработчикам в своих новых библиотеках (еще лучше и старые переделать) использовать такой же принцип обработки ошибок. Чуть позже опишу принцип подробнее. Основная идея состоит в том, чтобы использовать общий обработчик для обработки ошибок от всех библиотек.
Последний раз редактировалось ViNT, 10.04.2010 в 21:50.
|
(Offline)
|
|
Эти 5 пользователя(ей) сказали Спасибо ViNT за это полезное сообщение:
|
|
24.08.2009, 22:44
|
#2
|
ПроЭктировщик
Регистрация: 02.07.2008
Сообщений: 105
Написано 7 полезных сообщений (для 14 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
ViNT, спасибо за либу! Весьма полезна.
Но в процессе тестирования на реальных телефонах обнаружилось следующее:
1. Даже если не делать обработчик ошибок, всё равно на некоторых самсунгах может не запускаться. И через обфускатор proguard не проходит. Если создать хотя бы пустую процедуру onerror, то всё ОК. Надеюсь, эта информация пригодится тем, кто будет использовать данную либу.
2. Приём данных я делаю примерно так:
count := binsock.available; content := ''; while (count>0) do begin content := content + binsock.read_bin(count); count := binsock.available; end;
т.е. всё скачиваю в текстовую переменную.
Я так понял, что при загрузке сначала заполняется некий буфер, а потом уже из него можно скачивать в бинарный массив.
Подобный цикл while..end понадобился, поскольку размер буфера значительно меньше размера реально скачиваемого с сервера контента.
На эмуляторе kEmulator переменная count, отображающая binsock.available, принимает максимальное значение 8192. То есть когда я скачиваю с сервера 20 кб данных, цикл проходит 3 раза.
Но бинарная картинка, скачанная таким образом, нормально собирается и отображается на эмуляторе.
На мобильниках всё не так радужно. Например, на Samsung E-200 размер буфера всего 512 байт. Текстовый контент в приведённом мной выше цикле скачивается и собирается нормально, а вот картинка - нет, приходит битая.
Может, сможешь что-нибудь посоветовать?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
25.08.2009, 03:03
|
#3
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Спасибо за подробный баг-репорт, буду разбираться.
На счет некорректного приема картинки - надо бы сохранить данные в файл и сравнить с оригиналом, может станет понятно, в чем дело.
По поводу размера буфера - посмотрю, что по этому поводу написано в доках.
|
(Offline)
|
|
03.12.2009, 11:54
|
#4
|
AnyKey`щик
Регистрация: 02.12.2009
Сообщений: 18
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
а можно примерчит отправки скажем текста
на определённый айпишник, через udp
|
(Offline)
|
|
23.02.2010, 16:36
|
#5
|
AnyKey`щик
Регистрация: 25.06.2009
Сообщений: 2
Написано одно полезное сообщение
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Работает нормально, но при проверке на современных телефонах (SE C510 и некоторые Nokia) -не отправляет данные сразу. В процессе разбора полетов выяснилось-телефоны упорно буферизируют данные на отправку. Вылечилось добавлением
public static int write_byte(int data){
tx++;
try{
os.write(data);
os.flush(); <-----Вот этого
return 1;
}catch(Exception e){
err(e, ERR_WRITEERROR, "Error writing byte to stream");
return -1;
}
}
public static int write_bin(String data){
byte d[] = data.getBytes();
tx = tx+d.length;
try{
os.write(d);
os.flush(); <-----и этого
}catch(Exception e){
err(e, ERR_WRITEERROR, "Error writing binary to stream");
return -1;}
return 1;
}
|
(Offline)
|
|
23.02.2010, 22:44
|
#6
|
Мастер
Регистрация: 06.09.2007
Адрес: Донецк, ДНР
Сообщений: 1,023
Написано 298 полезных сообщений (для 713 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Да. FLUSH нужно делать обязательно.
На любых телефонах.
|
(Offline)
|
|
10.04.2010, 20:59
|
#7
|
AnyKey`щик
Регистрация: 10.04.2010
Сообщений: 2
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Сообщение от Topaz1977
Работает нормально, но при проверке на современных телефонах (SE C510 и некоторые Nokia) -не отправляет данные сразу. В процессе разбора полетов выяснилось-телефоны упорно буферизируют данные на отправку. Вылечилось добавлением
public static int write_byte(int data){
tx++;
try{
os.write(data);
os.flush(); <-----Вот этого
return 1;
}catch(Exception e){
err(e, ERR_WRITEERROR, "Error writing byte to stream");
return -1;
}
}
public static int write_bin(String data){
byte d[] = data.getBytes();
tx = tx+d.length;
try{
os.write(d);
os.flush(); <-----и этого
}catch(Exception e){
err(e, ERR_WRITEERROR, "Error writing binary to stream");
return -1;}
return 1;
}
|
Выложите пожалуйста исправленную версию кто нибудь.
|
(Offline)
|
|
10.04.2010, 21:51
|
#8
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Добавил функцию flush
|
(Offline)
|
|
10.04.2010, 21:54
|
#9
|
AnyKey`щик
Регистрация: 10.04.2010
Сообщений: 2
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Сообщение от ViNT
Добавил функцию flush
|
Спасибо! Очень оперативно!
|
(Offline)
|
|
27.04.2012, 18:47
|
#10
|
AnyKey`щик
Регистрация: 31.07.2011
Сообщений: 10
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
добрый день
спасибо за либу, пользую, работает отлично.
есть вопрос:
присылаю с сервера (delphi 2007, ServerSocket) текст с русскими буквами:
тел. НОКИА:
текст в ANSI: read_bin возвращает в строке символы ANSI, читаю посимвольно, преобразую в UTF8 - вопросов нет.
текст в UTF8: русские буквы приходят по 2 байта (как и положено)
тел. LG:
текст в ANSI: read_bin возвращает только часть строки ДО первой русской буквы
текст в UTF8: принимает на ура, даже преобразовывать ничего не надо.
ВОПРОС
каким образом можно оптимально заставить оба тел работать? сам я решение предполагаю, и не одно, но они мне не нравяться. LG при получении бинарного потока корректно распознает в нем русские буквы при копировании в строку, нокиа же, просто раскладывает - в каждый символ один байт.
буду признателен всем ответившим.
привожу свою функцию для преобразования данных из сокета в utf8 с русскими символами, может пригодиться кому нибудь. (функция фильтрует управляющие символы. этой же функцией можно читать русский текст из RecordStore)
function scr_frBIN(s: string): string; // (from BIN, ANSI to UTF)
var
i,l,co: integer;
ch: char;
re: string;
begin
re:= '';
l:= length(s)-1;
for i:=0 to l do begin
ch:= getChar(s,i);
co:= ord(ch);
if co>31 then
if co<127 then re:= re+ch
else if co>191 then re:= re+chr(co+848)
else if co=168 then re:= re+chr(1025)
else if co=184 then re:= re+chr(1105);
end;
scr_frBIN:= re;
re:= '';
end;
|
(Offline)
|
|
28.04.2012, 00:26
|
#11
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Просто режет строку, в обработчик ошибок ничего не сваливается, мидлет не зависает? Вообще, если режет символы даже в бинарном режиме, то вряд ли что-то модно сделать. Хотя, надо посмотреть, может и есть решение.
|
(Offline)
|
|
02.05.2012, 12:33
|
#12
|
AnyKey`щик
Регистрация: 31.07.2011
Сообщений: 10
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
провел тест на LG ( gw300 ):
binsock.debug_register(0);
binsock.enable_debug(-1);
ansi:
отправил: 123фф123
на тел:123? ( len = 4 )
utf-8:
отправил: 123фф123
на тел: 123фф123 ( len = 8 )
binsock.debug_register(1);
binsock.enable_debug(1);
результат тот же, ошибок нет. после получения русских "вопросиков" мидлет продолжает работать. вот исходник теста: (в первом тесте процедуры onerror не было)
program testscr;
uses
binsock;
var
IsConn, l : integer;
rx: string;
b: integer;
res: resource;
cmOK: command;
procedure onerror(sender:Integer;exception:string;errstr:string;code:integer);
begin
cmOK:= CreateCommand('OK',CM_OK,1);
ShowAlert('Error #'+IntegerToString(code),'Exception: '+exception+chr(10)+chr(13)+'ErrorString: '+errstr, LoadImage('/icon.png'),ALERT_ERROR);
repeat delay(200);
until getClickedCommand = cmOK;
end;
procedure clr;
begin
showCanvas;
setFont(FONT_FACE_SYSTEM, 0, FONT_SIZE_SMALL);
SetColor(0,0,0);
fillRect(0,0, getwidth, getheight);
SetColor(0,255,0);
end;
procedure txt(s: string; y: integer;);
begin
drawtext(s, 5, y);
repaint;
end;
begin
// scr
clr;
// сокеты
binsock.debug_register(1);
binsock.enable_debug(1);
// connect
IsConn:= binsock.open( 'socket://xxxx:2286' );
delay(3000);
if IsConn=1
then txt('connected!', 10)
else halt;
// loop
repeat
rx:= '';
// read sock
l:= binsock.available;
while l>0 do begin
rx:= rx + binsock.read_bin(l);
l:= binsock.available;
end;
// show
l:= length(rx);
if l>0 then begin
clr;
txt( integertostring(GetCurrentTime), 10 );
txt( 'rx len='+IntegerToString(l), 30 );
txt( rx, 50 );
end;
delay(100);
until GetKeyPressed <> KE_NONE;
end.
отправка с сервера в сокет выглядела так (delphi 2007):
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
us: UTF8String;
begin
us:= AnsiToUtf8( Edit1.Text );
for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do
if CheckBox1.Checked then // птичка "отправлять в utf-8"
ServerSocket1.Socket.Connections[i].SendText( us )
else
ServerSocket1.Socket.Connections[i].SendText( Edit1.Text );
end;
продолжил тесты:
функция binsock.read_byte возвращает именно байты. если пришел ansi - получим именно их коды, utf - по два байта на каждую русскую букву.
то есть засада в функции binsock.read_bin() - мне кажется, когда присваивается результат, NOKIA и LG воспринимают это по-разному: нокиа строго раскладывает побайтно, lg в этом потоке бинарных данных рассматривает utf8 символы и преобразует находу. можно ли и NOKIA заставить "распознавать" строку UTF-8 ?
Последний раз редактировалось AssA, 02.05.2012 в 13:43.
|
(Offline)
|
|
06.05.2012, 00:17
|
#13
|
Модератор
Регистрация: 03.04.2007
Сообщений: 2,252
Написано 597 полезных сообщений (для 817 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Совершенно непонятно, в чем дело. Скорее всего, какие-то внутренние особенности реализации обработки данных. Не думаю, что с этим можно что-то сделать.
|
(Offline)
|
|
28.05.2012, 17:26
|
#14
|
Оператор ЭВМ
Регистрация: 20.10.2009
Сообщений: 49
Написано 2 полезных сообщений (для 3 пользователей)
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Сообщение от AssA
провел тест на LG ( gw300 ):
binsock.debug_register(0);
binsock.enable_debug(-1);
ansi:
отправил: 123фф123
на тел:123? ( len = 4 )
utf-8:
отправил: 123фф123
на тел: 123фф123 ( len = 8 )
......
то есть засада в функции binsock.read_bin() - мне кажется, когда присваивается результат, NOKIA и LG воспринимают это по-разному: нокиа строго раскладывает побайтно, lg в этом потоке бинарных данных рассматривает utf8 символы и преобразует находу. можно ли и NOKIA заставить "распознавать" строку UTF-8 ?
|
1. На Delphi :
Перевожу русские буквы в base64, и отправляю в сокет ...Socket.Connections[i].SendText(AnsiToBase64('ваш текст' + '@')),
где например @ --- дополнительно обозначаю конец текста
function AnsiToBase64(S : String):String; var SS : string; begin SS:=Utf8Encode(S); SS:=EncodeBase64(SS); result:=SS; end;
где, Utf8Encode --- стандартная ф-ция библиотеки System
EncodeBase64 :
function EncodeBase64(Value: String): String; const b64alphabet: PChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; pad: PChar = '===='; function EncodeChunk(const Chunk: String): String; var W: LongWord; i, n: Byte; begin n := Length(Chunk); W := 0; for i := 0 to n - 1 do W := W + Ord(Chunk[i + 1]) shl ((2 - i) * 8); Result := b64alphabet[(W shr 18) and $3f] + b64alphabet[(W shr 12) and $3f] + b64alphabet[(W shr 06) and $3f] + b64alphabet[(W shr 00) and $3f]; if n <> 3 then Result := Copy(Result, 0, n + 1) + Copy(pad, 0, 3 - n); end; begin Result := ''; while Length(Value) > 0 do begin Result := Result + EncodeChunk(Copy(Value, 0, 3)); Delete(Value, 1, 3); end; end;
********************************************
2. На мобильном клиенте
Считываю данные,
Function ReadData():string; var k, i : integer; S:string; begin S:=''; K:=0; i:=binsock.available; if i=(-1) then begin ... ОШИБКА ПОЛУЧЕНИЯ ДАННЫХ end ELSE if i<>0 then BEGIN K:=0; repeat while ((ConnectError=true) and (binsock.available<>0) and (chr(k)<>'@')) do begin k := binsock.read_byte; if k=(-1) then begin ... ОШИБКА ПОЛУЧЕНИЯ ДАННЫХ end else if chr(k)<>'@' then S := S + chr(k); end; until ((ConnectError=false) or (chr(k)='@')); END; ReadData:=S; end;
Разкодирую данные в utf с помощью библиотеки proweb http://forum.boolean.name/showthread.php?t=8417
S:=base64_decode(S); S:=encode(S, 'utf-8', 'ошибка');
P.S. Как правило работает на всех телефоннах
|
(Offline)
|
|
13.08.2012, 14:09
|
#15
|
Оператор ЭВМ
Регистрация: 12.01.2011
Адрес: Воронеж
Сообщений: 32
Написано одно полезное сообщение
|
Ответ: Lib_binsock: прием/отправка бинарных данных через сокет
Возможно ли открытие одновременно более одного соединения?
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 22:48.
|