Konuyu Oyla:
  • Derecelendirme: 5/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Delphi ve Protocol Buffers
#1
Sık sık ihtiyaç duyduğumuz bir olaydır; yazdığımız iki uygulama arasında veri paylaşmak. İster iki uygulama da Delphi’de yazılmış olsun, ister farklı dillerde yazılmış olsun veri paylaşmak gerektiğinde verinin gönderiliş/alış şekli önemlidir. Bu gibi durumlarda verinin serileştirilmesi gerekir. Bunlardan en yaygın olanı XML ve JSON’dur.
Ben başka bir alternatiften daha söz etmek istiyorum: Protocol Buffers.
  • Google tarafından geliştirilmiştir.
  • Kısaca Protobuf olarak adlandırılır.
  • Açık kaynak kodludur: https://github.com/protocolbuffers/protobuf
  • Resmi olarak C++, C#, Java, Python, Objective-C, PHP, Javascript, GO, Ruby desteği mevcuttur.
  • Daha az yer kaplar, daha hızlıdır (Performans karşılaştırmaları için şuraya bakabilirsiniz)
  • Google’ın kendi uygulamaları arasındaki veri alışverişi için kullanıldığı gibi, Twitter, Spotify vs. dünya genelinde tanınmış bir çok firma tarafından kullanılmaktadır.
  • Bir çoğumuzun başını ağrıtan JSON-XML parse işlemlerinden kurtulmuş oluruz.


Örneğin siz uygulamanızdan kişi bilgilerini başka uygulamaya göndermek istiyorsunuz. Bunu Delphi’deki bir class, bir record yada veri tabanından alınan bir kayıt gibi düşünebilirsiniz. Kişinin Id’si, ismi, email adresi ve telefon numara(lar)ı olduğunu düşünelim.

Öncelikle bu veri yapısını Protobuf’ta tanımlamamız gerekir. Bunun için .proto uzantılı dosyalar kullanılır. Basit bir şeması vardır. Bizim örneğimiz için oluşturmamız gereken proto dosyası şöyle olabilir:
syntax = "proto3";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
  repeated string phonenumber = 4;
}
Görüldüğü gibi basit bir yapısı var, okunabilirliği çok kolay. Ama istenilirse çok detaylı veri yapıları oluşturulabilir. Detaylar için şuraya bakabilirsiniz: https://developers.google.com/protocol-b...ocs/proto3

Bir kişinin birden fazla telefon numarası olabileceği için phonenumber alanımızı repeated tanımladık.
Her alanımızın sonunda tekil bir numara veriyoruz. Bu numaralar tekil olmalı ve daha sonra değiştirilmemeli.
Bir message içinde başka bir message kullanabiliriz(nested).

Bundan sonra yapılması gereken; bu mesajı hangi programlama dilinde kullanmak istiyorsak onun için derlemek. Google bunun için protoc.exe adında bir araç geliştirmiş. Protobuf’ın GitHub linkinden istediğiniz işletim sistemi için indirme yapabilirsiniz.

Yukarıdaki örneğimizi person.proto adıyla kaydettiğimizi ve bu mesajları Java ve C# içinde kullanacağımızı varsayarsak:

protoc.exe  person.proto  --java_out=DIR_PATH  --csharp_out=DIR_PATH

Bu komutu çalıştırdığımızda DIR_PATH klasörü altında hem Java hem de C# dosyalarının oluştuğu görülür.


Yukarıda yazdığım gibi, desteklenen diller arasında maalesef Delphi yok Sad (Artık bu tarz şeylere pek de şaşırmıyoruz)

Delphi gibi resmi olarak desteklenmeyen diller için bir çok üçüncü parti çözümler üretilmiş ve onlar burada listelenmiştir. Ben Delphi için şunu kullanıyorum: https://github.com/kami-soft/ProtoBufGenerator

Bu kütüphaneyi indirip ProtoBufGenerator.exe'yi kullanarak yukarıda protoc.exe’nin yaptığı işlemi Delphi için yapabiliriz. Yani proto dosyasından pas dosyası üretebiliriz.
Yukarıdaki örnekten devam edecek olursak; person.proto'dan person.pas dosyasını elde ettik diyelim. Bu dosya içinde bizim Person mesajımız için TPerson sınıfının otomatik olarak oluşturulduğunu göreceksiniz.(Üstelik sınıf içinde yapılabilecek işlemler de otomatik olarak hazır Wink )

Basit bir sunucu-istemci örneği hazırladım. TCPClient ile mesajımız gönderip TCPServer ile okunuyor.

sonuc.gif


Client’an mesaj gönderme kısmı;
procedure TForm2.Button1Click(Sender: TObject);
var
 Person: TPerson;
 MS: TMemoryStream;
begin
 MS := TMemoryStream.Create;
 Person := TPerson.Create;
 try
   Person.id := 10;
   Person.name := 'DelphiCan';
   Person.email := 'info@DelphiCan.com';
   Person.phonenumberList.Add('05551234567');
   Person.phonenumberList.Add('02167777777');
   Person.phonenumberList.Add('7654321');
   Person.SaveToStream(MS);

   IdTCPClient1.Socket.Write(MS, 0, True);
 finally
   Person.Free;
   MS.Free;
 end;
end;

Sunucuda mesajı alma kısmı:
procedure TForm1. IdTCPServer1Execute(AContext: TIdContext);
var
 aPerson: TPerson;
 MS: TMemoryStream;
begin
 MS := TMemoryStream.Create;
 aPerson := TPerson.Create;
 try
   AContext.Connection.Socket.ReadStream(MS);
   aPerson.LoadFromStream(MS);
   // burada kişi bilgilerine erişebiliriz
   // aPerson.Id yada aPerson.name gibi
   // kişinin telefon numarası sayısı aPerson.phonenumberList.Count
   // kişinin ilk telefon numarası aPerson.phonenumberList[0]
 finally
   aPerson.Free;
   MS.Free;
 end;
end;

Görüldüğü gibi XML yada JSON parse’deki zahmetli işlerle uğraşmak zorunda kalmıyoruz. Her şey otomatik olarak oluşturulmuş sınıflarımız içerisinde mevcut. (Mesela yukaridaki örnekte telefon numarlarının tutulduğu phonenumberList otomatik oluşturulmuştur)
Bu kullanımın güzelliği daha karmaşık mesajlar göndermek istediğinizde ortaya çıkacaktır. Proto dosyası içinde message içinde başka bir message (nested) kullanabilmeniz size çok büyük esneklik katacaktır.
Protobuf’ın bir başka güzelliği ise; mesaj içinde değişiklik yaptığınızda eski versiyon mesajlarınızla da çalışmaya devam edebiliyorsunuz! Yeni bir alan ekleyebilirsiniz, var olanı silebilirsiniz vs.

Özellikle farklı programlama dilleri arasında mesajlaşma gerektiğinde çok daha faydalı olduğunu görebilirsiniz. Karşı taraf hangi dili kullanıyorsa protoc.exe ile o dil için çıktı üretip karşı tarafa bunu veriyoruz.


ProtoBuf böyle kısa bir makaleye sığdırılamayacak kadar güzel ve detaylı bir projedir. Ben sadece giriş mahiyetinde bilgilendirme yapmaya çalıştım. Umarım ilgilenen çıkar Blush

Örnek projenin kaynak kodlarını buradan indirebilirsiniz:
https://yadi.sk/d/Xhq5K0MRhASeFw
There's no place like 127.0.0.1
WWW
Cevapla
#2
Hocam çok teşekkür ederim. harika bir anlatım olmuş. Elinize, emeğinize sağlık.
Yazılımcı, kahveyi koda çeviren bir organizmadır.
Cevapla
#3
Teşekkürler faydalı ve güzel bir paylaşım için.
Cevapla
#4
Ellerine sağlık güzel kardeşim. Mobil ortamdan bakıyorum, dolayısı ile detaylı bir inceleme şansım olmadı; lâkin bizim Delphi içinde tanımladığımız sınıfları Rest.Json unit’i içindeki TJson sınıfı ile serialize/deserialize etmek gözüme daha kolay göründü.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#5
Elinize sağlık hocam, güzel anlatım.
WWW
Cevapla
#6
(27-05-2019, Saat: 19:33)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Ellerine sağlık güzel kardeşim. Mobil ortamdan bakıyorum, dolayısı ile detaylı bir inceleme şansım olmadı; lâkin bizim Delphi içinde tanımladığımız sınıfları Rest.Json unit’i içindeki TJson sınıfı ile serialize/deserialize etmek gözüme daha kolay göründü.

Alışınca tadından yenmez Big Grin

Kolaylıktan ziyade ProtoBuf'ın asıl avantajı az yer kaplaması ve hızı. Sıradan bir proje için bunlar önem arz etmeyebilir ama Google Maps gibi bir projede bu yüzden ProtoBuf kullanılır. Yada giderek büyük bir hızla yayılan IOT dünyasında, büyük çapta bir projeye girildiğinde, sahada kullanılan binlerce cihazdan gelen/giden veri düşünüldüğünde harcanan bandwidth'in ne kadar önemli olduğu malumdur. 

Ben ProtoBuf'tan bahsettim, benden günah gitti Big Grin Big Grin
There's no place like 127.0.0.1
WWW
Cevapla
#7
Elinize saglik
Cevapla
#8
Makale icin ellerinize saglik. Gorebildigim kadariyla C#'da mevcut olan binary serilization mantigini kullaniyor. Belirttiginiz gibi tanim dosyasinin sonuna artan sirada yeni alan eklemek sorun olmaz. Ancak alan tipi degistiginde, araya alan eklendiginde sorun olacaktir, kullanirken dikkatli olmak lazim.
Cevapla
#9
Bu sistem sadece LAN üzerinde mi çalışıyor yoksa internete bağlı iki kullanıcı arasında da geçerli mi ?
D7'nin Demo programlarında NetChat diye bir program demosu vardı. Client Server bağlantısı üzerinden sadece LAN üzerinde Chat benzeri bir haberleşme sağlıyordu. Ona benziyor.
Cevapla
#10
Konunun network iletisimi ile ilgisi yok. Konu objeleri veri olarak kaydedip tekrar olusturabilmekten ibaret. Veriyi ister LAN uzerinden gonderin ister eposta atin, ister db'ye kaydedin.
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  Delphi ile .Net Ortamında geliştirilen dll içerisindeki fonksiyon kullanımı yhackup 10 8.066 09-04-2023, Saat: 02:17
Son Yorum: gogo72
  Delphi AES 128 ECB PKCS5 Padding ile sorun aegean 1 835 28-11-2022, Saat: 13:07
Son Yorum: aegean
  Delphi IDE'sine Eklenti Yapmak - 2 SimaWB 29 21.991 03-07-2022, Saat: 16:40
Son Yorum: enigma
  Delphi ile İşletim Sistemi Yazımı PROGRAMADOR35 13 8.180 26-09-2021, Saat: 21:29
Son Yorum: ekremkocak
  Delphi ile Scada Milenyumotomasyon 18 10.163 28-07-2021, Saat: 10:53
Son Yorum: mehkamaci



Konuyu Okuyanlar: 1 Ziyaretçi