По поводу примеров использования TTransportServer AllLib содержит ядро поддержки транспорта (алгоритм серерной части, алгоритм клиентской, поддержка хранилища в базе данных, поддержка аутентификации, передача по http/https). Работающие примеры по TTransportServer/TTransportClient являются частью разрабатываемого продукта, поэтому здесь приводятся только вырезки кода из них. 1. Серверная часть http-транспорта работает под IIS в Windows 2000/2003 Server и представляет собой asp-скрипт + ActiveX-компонент, вызывающий методы TBaseTransportWebPage (использующего внутри TTransportServer), вот основная часть кода asp: в WTS - записывается интерфейс ActiveX-компонента, с помощью которого вызываются одноименные глобальные функции или методы TBaseTransportWebPage IF WTS.ToStr(WTS.CommonVars("IsBinary")) = "" THEN call WTS.SetCommonVar("IsBinary", True) END IF call WTS.SetVar("ServerId", "INTERNET") call WTS.SetVar("MsgMaxCount", 32760) call WTS.SetVar("MsgMaxSize", (1024 * 1024) * 3 \ 4) ' Define ASP objects call WTS.SetVar("ASPApplication", Application) call WTS.SetVar("ASPObjectContext", ObjectContext) call WTS.SetVar("ASPRequest", Request) call WTS.SetVar("ASPResponse", Response) call WTS.SetVar("ASPServer", Server) call WTS.SetVar("ASPSession", Session) ' Turn cache off, set timeout to 3 hours, define content type Response.Expires = -1 Server.ScriptTimeout = 900 IF WTS.ToBool(WTS.CommonVars("IsBinary")) THEN Response.ContentType = "application/octet-stream" call WTS.SetVar("BinaryParams", _ WTS.ToByteStr(Request.BinaryRead(Request.TotalBytes))) END IF ' Load parameters from ini-files and define defaults call WTS.Fnc("LoadParams") ' Authentificate Client call WTS.Fnc("Auth") ' Process Web Transport delivery request and return result to page call WTS.Fnc("Delivery") LoadParams - грузит параметры из ini-шки, см. код метода; смысл, в общем - задать в Vars['ConnectionString'] - строку соединения ADO с базой данных и задать в Vars['AuthAlg'] - алгоритм аутентификации ('RSA128' - стандартный Microsoft RSA Cryptoprovider, 'GOST', 'GOST2001' - КриптоПро CSP+TLS (сервер) или 'SCOM' - Сигнал-КОМ Inter-PRO) Auth - проводит аутентификацию - по параметрам Владельца (subject*) и Издателя (issuer*) сертификата в таблице (см. ниже) ищется ID организации CREATE TABLE CERTOWNERS( CO_ID char(46) NOT NULL , CO_TYPE char(3), CO_ORGANIZATIONID varchar(46), CO_USERLOGIN varchar(46), CO_SUBJECTCN varchar(64), CO_SUBJECTT varchar(64), CO_SUBJECTOU varchar(64), CO_SUBJECTO varchar(64), CO_SUBJECTL varchar(128), CO_SUBJECTS varchar(128), CO_SUBJECTC varchar(2), CO_SUBJECTE varchar(128), CO_SUBJECTOTHER varchar(255), CO_ISSUERCN varchar(64), CO_ISSUERT varchar(64), CO_ISSUEROU varchar(64), CO_ISSUERO varchar(64), CO_ISSUERL varchar(128), CO_ISSUERS varchar(128), CO_ISSUERC varchar(2), CO_ISSUERE varchar(128), CO_ISSUEROTHER varchar(255) ) Далее организация ищется в таблице: CREATE TABLE CLIENTS( CL_ID char(46) NOT NULL , CL_NAME varchar(128), CL_ISINUSE int, CL_LOGIN varchar(46), CL_ARMTYPES char(3) ) Нужно: CL_ISINUSE = 1 (т.е. включена), CL_ARMTYPES = 'W', в CL_LOGIN можно записать то же, что в CL_ID Наконец, Delivery производит обмен (читает из параметров asp, что пришло с клиента, и отправляет в тексте ответа, что должен послать сервер). Таблица документов имеет следующую структуру (описание полей есть в коде GDifUtil.pas; очень кратко - см. ниже): CREATE TABLE MAILDOCUMENTS( MD_DOCID varchar(46) NOT NULL, MD_OWNERORGID varchar(46) NOT NULL, MD_OPPOSITEORGID varchar(46) NOT NULL, MD_OUTGOING int NOT NULL, MD_DATE datetime, MD_SENT int, MD_CONFIRMED int, MD_ERROR int, MD_REPEATED int, MD_PROCESSED int, MD_ARCDOCID varchar(46), MD_ARCOPPOSITEORGID varchar(46), MD_BODY image ) ON GO ALTER TABLE MAILDOCUMENTS ADD CONSTRAINT PK_MAILDOCUMENTS PRIMARY KEY ( MD_DOCID, MD_OWNERORGID, MD_OPPOSITEORGID, MD_OUTGOING ) GO Инициализация в ActiveX сервера: FCommonVars := TVariantParams.Create; FFileOperations := GDifUtil.FileOperations; FFileOperations.IsFileSafe := ErrorObject.IsFileSafe; FFileOperations.FileSafeInfo := ErrorObject.FileSafeInfo; FFileOperations.ReadOnlyFileSafeInfo := ErrorObject.ReadOnlyFileSafeInfo; FFileOperations.WriteOnlyFileSafeInfo := ErrorObject.WriteOnlyFileSafeInfo; FTransportWebPage := TTransportWebPage.Create; FTransportWebPage.OwnsWWW := True; FTransportWebPage.OwnsVars := True; FTransportWebPage.CommonVars := ACommonVars; FTransportWebPage.FileOperations := FileOperations; FTransportWebPage.InitFinish; Освобождение объектов: FTransportWebPage.Free; FCommonVars.Free; 2. Клиентская часть http-транспорта строится на основе TTransportWebClient (наследника TTransportClient), вот кусок кода инициализации: FTransportWebClient := TTransportWebClient.Create; FTransportWebClient.Storage := TTransportDBStorage.Create; TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess := TADODatabaseAccess.Create(Unassigned, ''); ini := TIniFileStd.Create(ChangeFileExtStd(ParamStr(0), '.ini')); try FTransportWebClient.Link := Param(ini, 'HTTP', 'HTTP_LINK'); FTransportWebClient.Login := Param(ini, 'HTTP', 'HTTP_LOGIN'); FTransportWebClient.Password := Param(ini, 'HTTP', 'HTTP_PASSWORD'); FTransportWebClient.ParentHandle := Handle; FTransportWebClient.ConfigName := TrimStd(Param(ini, 'HTTP', 'HTTP_CONFIGNAME')); FTransportWebClient.BlockSize := StrToIntDefStd( Param(ini, 'HTTP', 'HTTP_BLOCKSIZE'), FTransportWebClient.BlockSize); FTransportWebClient.IsBinary := (StrToIntDefStd( Param(ini, 'HTTP', 'HTTP_ISBINARY'), Ord(FTransportWebClient.IsBinary)) = Ord(True)); FTransportWebClient.MaxCount := StrToIntDefStd( Param(ini, 'HTTP', 'HTTP_MAXCOUNT'), FTransportWebClient.MaxCount); FTransportWebClient.MaxSize := StrToIntDefStd( Param(ini, 'HTTP', 'HTTP_MAXSIZE'), FTransportWebClient.MaxSize); TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess. Database := Param(ini, 'HTTP', 'HTTP_DATABASE'); TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess. ConnectionString := Param(ini, 'HTTP', 'HTTP_CONNECTIONSTRING'); FTransportWebClient.Storage.OwnerId := TrimStd(Param(ini, 'HTTP', 'HTTP_CLIENTID')); FTransportWebClient.Storage.OwnerPrefix := TrimStd(Param(ini, 'HTTP', 'HTTP_CLIENTPREFIX')); FTransportWebClient.Storage.OppositeId := IfEmpty(TrimStd(Param(ini, 'HTTP', 'HTTP_SERVERID')), 'INTERNET'); FTransportWebClient.Storage.OppositePrefix := ''; if CompareStrUpper(FTransportWebClient.Storage.OwnerId, FTransportWebClient.Storage.OppositeId) = 0 then FTransportWebClient.Storage.OppositeId := ''; FTransportWebClient.SrvDatabase := TrimEmpty(Param(ini, 'HTTP', 'HTTP_SRVDATABASE')); FTransportWebClient.SrvConnectionString := TrimEmpty(Param(ini, 'HTTP', 'HTTP_SRVCONNECTIONSTRING')); if FTransportWebClient.SrvConnectionString = '' then if not StrStartFromUpper('https://', FTransportWebClient.Link) then if StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_NORUNCRYPTO'), Ord(False)) <> Ord(True) then try s := InterProInfo(0).Path; if TrimStd(s) <> '' then RunProcessChecked(s + 'intpro.exe', '', True, 1000); except on EWinAPIError do; end; if FTransportWebClient.SrvConnectionString <> '' then begin FTransportWebClient.Storage.IsMulti := True; FTransportWebClient.TransportServer.Storage.IsMulti := True; end; {$IFNDEF VER80} {$IFNDEF VER90} {$IFNDEF VER93} {$IFNDEF VER100} if FTransportWebClient.SrvConnectionString <> '' then begin FTransportWebClient.CompressionLevel := clNone; FTransportWebClient.CompressExceededOnly := False; end else case StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_COMPRESSMODE'), Ord(True)) of 1: begin FTransportWebClient.CompressionLevel := clDefault; FTransportWebClient.CompressExceededOnly := False; end; 2: begin FTransportWebClient.CompressionLevel := clDefault; FTransportWebClient.CompressExceededOnly := True; end; 3: begin FTransportWebClient.CompressionLevel := clFastest; FTransportWebClient.CompressExceededOnly := False; end; 4: begin FTransportWebClient.CompressionLevel := clFastest; FTransportWebClient.CompressExceededOnly := True; end; else FTransportWebClient.CompressionLevel := clNone; FTransportWebClient.CompressExceededOnly := False; end; {$ENDIF} {$ENDIF} {$ENDIF} {$ENDIF} TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess. MaxBLOBSize := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_MAXBLOBSIZE'), High(Integer)); TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess. ConnectionTimeout := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_CONNECTIONTIMEOUT'), 300); TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess. CommandTimeout := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_COMMANDTIMEOUT'), 600); FTransportWebClient.SrvMaxBLOBSize := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_SRVMAXBLOBSIZE'), High(Integer)); FTransportWebClient.SrvConnectionTimeout := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_SRVCONNECTIONTIMEOUT'), 300); FTransportWebClient.SrvCommandTimeout := StrToIntDefStd(Param(ini, 'HTTP', 'HTTP_SRVCOMMANDTIMEOUT'), 600); debug_info_ptr := DebugInfo; if Assigned(debug_info_ptr) then begin debug_info_ptr^.Mode := debug_info_ptr^.Mode + [dmNoConsole]; debug_info_ptr^.DebuggingClasses := Param(ini, 'HTTP', 'HTTP_DEBUGMODE'); debug_info_ptr^.FileName := AddFilePath(Param(ini, 'HTTP', 'HTTP_DEBUGFILE'), ExtractFilePathStd(ParamStr(0)), False, False); end; finally ini.Free; end; FTransportWebClient.OnProcessMessages := ProcessMessages; FTransportWebClient.OnClientCertRetrieve := CryptoAPI.ClientCertContextRetrieve; Здесь задаются параметры - важно задать Link - http-ссылка на серверный asp-скрипт, ConnectionString - строка соединения ADO с базой клиента, OwnerId - ID клиентской организации, OppositeId - ID серверной организации (в данном примере - 'INTERNET') [сначала создается TTransportWebClient - логика работы приема/отправки, потом TTransportDBStorage - логика работы с хранилищем сообщений - таблицей MAILDOCUMENTS, заполняются свойства объктов (документированные в их объявлениях)] Далее вызов собственно обмена (ищет в MAILDOCUMENTS клиентской базы, что нужно отправить, отсылает по http, принимает ответ сервера, кладет в MAILDOCUMENTS клиентской базы): FTransportWebClient.Delivery([dmSend, dmReceive]); И освобождение объектов: if Assigned(FTransportWebClient) then begin if Assigned(FTransportWebClient.Storage) then begin if FTransportWebClient.Storage is TTransportDBStorage then if Assigned(TTransportDBStorage(FTransportWebClient.Storage). DatabaseAccess) then TTransportDBStorage(FTransportWebClient.Storage).DatabaseAccess.Free; FTransportWebClient.Storage.Free; end; FTransportWebClient.Free; end; Если ссылка (свойство Link) начинается с https://, то используется RSA/КриптоПро, параметры сертификата ищутся по CERTOWNERS для заданного ID органризации OwnerId, и по найденным параметрам ищется сертификат в хранилище CryptoAPI (Свойства обрзревателя/Содержание/Сертификатов). Если ссылка начинается на http://, то используется Сигнал-КОМ Inter-PRO, в котором в самом прописываются нужные сертификаты, поэтому таблица CERTOWNERS на клиенте в этом случае не нужна. Таблица CLIENTS на клиенте не используется. Таблица MAILDOCUMENTS (точно такой же структуры, как и на сервере) на клиенте - естественно, используется. Заполнение полей: MD_DOCID - идентификатор документа MD_OWNERORGID - собственный идентификатор организации (т.е. на клиенте - ИД клиента, заведенной в CLIENTS на сервере) MD_OPPOSITEORGID - идентификатор организации получателя (т.е. на клиенте - ИД сервера ,тобычно 'INTERNET', заводить нигде не надо) MD_OUTGOING - задать 1 - для исходящих документов; 0 - у пришедших с сервера MD_DATE - дата MD_SENT - задать 0, сюда пишется количество попыток отсылки (в случае disconnect'ов и т.п.) MD_CONFIRMED - задать 0, после успешной отправки (или приема) сюда запишется 1 (а в процессе отправки еще пишется 2) MD_ERROR - задать 0, при ошибке отправки (т.е. если на сервере уже есть документ с таким ID и другим содержимым) сюда запишется 1 MD_REPEATED - задать 0 MD_PROCESSED - задать 0, при обработке принятых или факта доставки отправленных - сюда можно писать 1, помечая то, что уже обработано MD_ARCDOCID - null (или ID документа, содержимое которого нужно при пересылке добавить к содержимому данного, в конец) MD_ARCOPPOSITEORGID - null (или ID получателя у документа, содержимое которого нужно при пересылке добавить к содержимому данного, в конец) MD_BODY - BLOB с содержимым документа, которое нужно переслать или которое было получено Алгоритм работы транспортов гарантирует, что все документы из MAILDOCUMENTS клиента (адресованные серверу) будут доставлены до сервера (и все документы на сервере для данного клиента будут им получены). Для скорости документы пересылаются объединенными в пакеты размером, по умолчанию, до (1024 * 1024) * 3 / 4 байт (или больше - если размер отдельного документа оказался больше - тогда такой документ составит отдельный пакет). При разрыве связи - пакет будет передан снова в следующем сеансе (докачки нет; хотя используется сжатие ZLib - стандартной библиотекой в составе Delphi5 и выше, не требующей внешних dll). Серверная часть http-транспорта разработана под стандартный для Windows веб-сервер IIS, чтобы не делать самостоятельно реализованную в нем балансировку нагрузки и т.п. При этом основная проблема - что веб-сервер, отправляя данные клиенту по http - не знает, дошли ли они полностью до клиента. Поэтому в алгоритме транспорта используется механизм подтверждений - сначала посылается сам документ, потом подтверждение об успешном приеме/отправке (подробнее см. в модуле TTransportMessage, комментариях к TTransportMessage). Прием или отправка для документа завершены - если MD_CONFIRMED = 1 (успешно доставлен) или если MD_ERROR = 1 (документ нельзя отправить, т.к. в базе противоположной стороны уже есть документ с таким же ID) На основе базовых классов TTransportClient, TTransportServer, TTransportDBStorage, конечно, можно написать и другой (не-http) транспорт, но пока не возникало потребности. P.S. В исходниках серверного транспорта недавно обнаружилась ошибка, проявившаяся при работе через CryptoAPI. В GExtUtil.pas - в TBaseTransportWebPage.Destroy нужно удалить код: if Assigned(FCryptoService) then FCryptoService.Free; (а в TBaseTransportWebPage.Create можно удалить FCryptoService := nil; - хотя это уже не существенно)