• Delphi'deki yuvalar. Delphi yuvalarıyla çalışmak için Delphi Bileşenlerinde yuva programlama

    Soketler (soketten (İngilizce) - konnektör, soket), süreçler arasında bilgi alışverişini sağlayan bir yazılım arayüzüdür.

    Bir ağda soket iletişiminin ana avantajlarından biri esnekliğidir. Yuvalarla çalışmanın temel ilkesi, başka bir bilgisayara bir bayt dizisi göndermektir, bu basit bir metin mesajı veya bir dosya olabilir.

    İki tür soket arasında ayrım yapmak önemlidir: istemci yuvaları , Ve sunucu yuvaları .

    Delphi'de "istemci" tipi soketlerle çalışmak için bir bileşen vardır. TClientSocket, bileşeni kullanarak "sunucu" soketleriyle çalışabilirsiniz TServerSocket.

    Bileşenleri yükleme

    Genellikle TServerSocket ve TClientSocket bileşenleri, standart Delphi kurulum paketine dahil değildir, ancak ayrı olarak kurulabilirler.

    "İnternet" bileşenleri sekmesine gidin ve TServerSocket ve TClientSocket bileşenlerinin orada olup olmadığını kontrol edin, yoksa kurun. "Bileşen/Kurulum Paketleri" menüsüne gidin, ardından "Ekle" düğmesini tıklayın. Açılan iletişim kutusunda, "dclsocketsXX.bpl" dosyasını (Delphi klasöründe bulunan bin klasöründe bulunur) bulmanız gerekir; burada XX, Delphi'nizin sayısal sürüm numarasıdır. Dosyayı bulun, Aç'a tıklayın ve ardından Paketleri Yükle penceresinde Tamam'a tıklayın. Şimdi, "İnternet" sekmesinde iki bileşen belirdi - TServerSocket ve TClientSocket.

    İstemci yuvalarıyla çalışma (tClientSocket)

    1) Port ve Host özelliklerinin tanımı. Başarılı bir bağlantı özellikleri için liman Ve Ev sahibi TClientSocket bileşenine bazı değerler atanmalıdır. Port özelliğinde, bağlantı için port numarasını belirtmeniz gerekir (1 - 65535, ancak 1001 - 65535 aralığından almak daha iyidir, çünkü 1000'e kadar olan sayılar sistem hizmetleri tarafından işgal edilebilir).

    Ev sahibi- bağlanmak istediğiniz bilgisayarın ana bilgisayar adı veya IP adresi. Örneğin, rus.delphi.com veya 192.128.0.0.

    2) Bir yuva açmak. Soketi, bir bilgisayardan diğerine iletilen bir karakter sırası olarak ele alacağız. Yöntemi çağırarak bir soket açabilirsiniz. açık(TClientSocket bileşeni) veya bir değer atayarak Doğru mülk Aktif. Burada, başarısız bir bağlantı olması durumunda bir istisna işleyicisi koymak faydalı olacaktır.

    3) Veri gönderme/alma.

    4) Soketin kapatılması. Veri alışverişi tamamlandıktan sonra, yöntemi çağırarak soketi kapatmanız gerekir. kapalı bileşen TClientSocket veya bir değer atayarak YANLIŞ mülk Aktif.

    TClientSocket bileşeninin temel özellikleri

    Soketin açık mı yoksa kapalı mı olduğunun bir göstergesi. Açık - Gerçek değer, kapalı - Yanlış değer. Kayıt için kullanılabilir.

    Bağlanmak için ana bilgisayar adı

    Bağlanılacak bilgisayarın IP adresi. Host'tan farklı olarak, burada yalnızca IP belirtilebilir. Aradaki fark, Ana Bilgisayar gerçek bir bilgisayar adı içeriyorsa, IP'nin DNS'den istenmesidir.

    Bağlanılacak bilgisayarın bağlantı noktası numarası (1-65535)

    İstemci Türü

    Veri aktarım türünü içerir:

    ctBlocking- senkronize iletim ( Okumada Ve Yazıdaçalışmıyor). Eşzamanlı bağlantı türü, akışlı veri alışverişi için uygundur;

    ctNonBlocking- eşzamansız iletim (veri gönderme / alma olayları kullanılarak yapılabilir Okumada Ve Yazıda)

    TClientSocket Bileşeninin Temel Yöntemleri

    Bir yuva açar (Active özelliğini True olarak ayarlar)

    Soketi kapatır (Active özelliğini False olarak ayarlar)

    TClientSocket bileşeninin ana olayları

    Bağlantıda

    Bir bağlantı kurulduğunda gerçekleşir. İşleyicide, zaten yetkilendirmeye veya veri göndermeye / almaya başlayabilirsiniz

    Bağlanıyor

    Bağlandığında da oluşur. Bağlantının henüz kurulmamış olması nedeniyle OnConnect'ten farklıdır. Çoğu zaman, örneğin durumu güncellemek için kullanılır

    Bağlantı Kesildiğinde

    Olay, soket programınız, uzak bilgisayar veya bir arıza nedeniyle kapatıldığında gerçekleşir.

    Olay bir hatada ortaya çıkar. Soket açılırken bu olay hatayı yakalamaya yardımcı olmaz. Windows'tan bir hata mesajı almamak için, açık ifadeleri " dene..hariç »

    Aramada

    Olay, DNS'den bir IP adresi almaya çalışırken meydana gelir.

    Olay, uzaktaki bir bilgisayar size bazı veriler gönderdiğinde gerçekleşir. OnRead'i çağırırken, alınan verileri işlemek mümkündür

    Programınızın sokete veri yazmasına izin verildiğinde olay ortaya çıkar.

    giriiş

    Bu makale, Borland Delphi'de soket tabanlı istemci/sunucu uygulamaları oluşturmakla ilgilidir. Ve bu makaleyi bir nedenle yazdım, ama çünkü son zamanlarda bu soru birçok kişinin ilgisini çekmeye başladı. Şimdilik sadece socket uygulamasının client kısmının oluşturulmasına değineceğiz.
    Prizlerle ilk kez yanılmıyorsam bir buçuk yıl önce tanıştım. Ardından görev, bir sunucu makinesine (Unix/Linux OS üzerinde çalışan) bir istek gönderecek ve bir soket kanalı aracılığıyla bir yanıt alacak bir uygulama protokolü geliştirmekti. Unutulmamalıdır ki, diğer protokollerden (FTP, POP, SMTP, HTTP, vb.) farklı olarak, soketler bu protokollerin temelidir. Böylece, soketleri kullanarak, FTP, POP ve diğer protokolleri kendiniz oluşturabilir (simüle edebilirsiniz) ve önceden oluşturulmuş olması gerekmez, hatta kendi protokolünüzü bile oluşturabilirsiniz!

    Öyleyse teori ile başlayalım. Eğer sadık bir uygulayıcıysanız (ve herhangi bir algoritmayı gözünüzle göremiyorsanız), o zaman bu bölümü atlamalısınız.

    Soket protokolleriyle çalışmak için algoritma

    Peki prizler ne yapmamızı sağlıyor?... Evet, her şey! Ve bu, ağdaki bu veri alışverişi yönteminin ana avantajlarından biridir. Gerçek şu ki, bir soketle çalışırken, başka bir bilgisayara bir dizi karakter gönderirsiniz. Yani bu yöntemle hem basit mesajları hem de tüm dosyaları gönderebilirsiniz! Ayrıca, aktarımın doğruluğunu kontrol etmenize gerek yoktur (COM bağlantı noktalarıyla çalışırken olduğu gibi)!
    Delphi uygulamalarında yuvalarla çalışmak için yaklaşık bir şema aşağıdadır:

    Host ve Port özelliklerini tanımlama >>> Bir Soket Başlatma (ClientSocket1.Open) >>> Yetkilendirme >>> Veri gönderme/alma >>> Bir Soketi Kapatma

    Şemayı daha ayrıntılı olarak inceleyelim:
    Ana Bilgisayar ve Bağlantı Noktasındaki özelliklerin belirlenmesi - başarılı bir bağlantı kurmak için, gerekli değerleri TClientSocket bileşeninin Ana Bilgisayar ve Bağlantı Noktası özelliklerine atamanız gerekir. Ana bilgisayar, bağlanılacak bilgisayarın ana bilgisayar adı (örneğin: nitro.borland.com) veya IP adresidir (örneğin: 192.168.0.88). Bağlantı noktası - bağlantı kurulumu için bağlantı noktası numarası (1'den 65535'e kadar). Genellikle port numaraları 1001'den başlayarak alınır - çünkü 1000'den küçük sayılar sistem hizmetleri tarafından kullanılabilir (örneğin, POP - 110). Pratik bölümle ilgili ayrıntılar için aşağıya bakın;
    Soket açma - Host ve Port özelliklerine uygun değerleri atadıktan sonra, doğrudan soket açmaya devam edebilirsiniz (burada soket, bir bilgisayardan diğerine iletilen karakterleri içeren bir sıra olarak kabul edilir). Bunu yapmak için TClientSocket bileşeninin Open yöntemini çağırabilir veya Active özelliğini True olarak ayarlayabilirsiniz. Burada, bağlantının başarısız olması durumunda bir istisna işleyicisi koymak faydalıdır. Bununla ilgili daha fazla bilgiyi aşağıdaki pratik kısımda okuyabilirsiniz;
    Yetkilendirme - sunucu herhangi bir oturum açma ve / veya parola gerektirmiyorsa bu öğe atlanabilir. Bu aşamada, kullanıcı adınızı (kullanıcı adı) ve şifrenizi sunucuya gönderirsiniz. Ancak yetkilendirme mekanizması belirli bir sunucuya bağlıdır;
    Veri gönderme / alma - aslında soket bağlantısının açılması bunun içindi. İletişim protokolü ayrıca sunucuya bağlıdır;
    Soketi kapatma - gerçekleştirilen tüm işlemlerden sonra, TClientSocket bileşeninin Close yöntemini kullanarak soketi kapatın (veya Active özelliğini False olarak ayarlayın).

    TClientSocket bileşeninin özelliklerinin ve yöntemlerinin açıklaması

    Burada TClientSocket bileşeninin ana özelliklerini, yöntemlerini ve olaylarını tanıyacağız.

    Özellikler
    Aktif - Soketin açık olup olmadığını gösterir. Tür: Boole. Buna göre True açık, False kapalıdır. Bu özellik yazılabilir;
    Ana bilgisayar - bağlanılacak bilgisayarın ana bilgisayar adını gösteren bir dize (Tür: dize);
    Adres - bağlanılacak bilgisayarın IP adresini gösteren bir dize (Tür: dize). Host'tan farklı olarak, burada yalnızca IP bulunabilir. Aradaki fark, Host'ta sembolik bir bilgisayar adı belirtirseniz, bu ada karşılık gelen IP adresinin DNS'den istenmesidir;
    Bağlantı noktası - bağlantı noktası numarası (Tür: Tamsayı (Word)) bağlanılacak. Geçerli değerler 1 ile 65535 arasındadır;
    Hizmet - bağlantının yapılacağı bağlantı noktası hizmetini (ftp, http, pop vb.) belirten bir dize (Tür: dize). Bu, bağlantı noktası numaralarını çeşitli standart protokollerle eşleştirmek için bir tür referans kitabıdır;
    ClientType - bağlantı türü. ctNonBlocking - eşzamansız veri aktarımı, yani OnRead ve OnWrite kullanarak soket üzerinde aynı anda veri gönderip alabilirsiniz. ctBlocking - senkronize veri aktarımı. OnRead ve OnWrite olayları çalışmıyor. Bu tür bir bağlantı, akışları kullanarak veri alışverişini organize etmek için kullanışlıdır (yani, dosya olarak bir soketle çalışmak);

    Yöntemler
    Aç - bir yuva açmak (True değerini Active özelliğine ayarlamaya benzer);
    Kapat - soketi kapatır (Active özelliğine False değerinin ayarlanmasına benzer);

    Bunun üzerine, TClientSocket bileşeninin tüm yöntemleri tükenir. Ve soruyorsunuz: "Ama bir soketle nasıl çalışılır? O zaman nasıl veri gönderilir?". Bu konuda biraz daha fazla bilgi edineceksiniz.

    Uygulama ve örnekler

    Herhangi bir programlama tekniğini öğrenmenin en kolay (ve en ödüllendirici) yolu, onu yapmaktır. Bu nedenle, aşağıdaki örnekler bazı yorumlarla verilmiştir:

    Örnek 1. En basit soket programı

    (Form içerisine bir TButton butonu ve iki adet TEdit yerleştirmeniz gerekmektedir. Butona tıklandığında OnClick - Button1Click olay işleyicisi çağrılır. Ondan önce TEdit'lerin ilk kısmına host adını ve portunu girmeniz gerekmektedir. uzak bilgisayarın ikinci saniyesinde.BİLEŞENİ TClientSocket FORMUNA KOYMAYI UNUTMAYIN !}


    başlamak
    (Host ve Port özelliklerine istenilen değerleri atarız)
    ClientSocket1.Host:= Edit1.Text;
    ClientSocket1.Port:= StrToInt(Edit2.Text);
    (Soket açıp bağlantı kurmaya çalışmak)
    ClientSocket1.Open;
    son;


    başlamak
    (Bağlantı yapılır yapılmaz soketi kapatıp bağlantıyı kesiyoruz)
    ClientSocket1.Close;
    son;

    Bu örnek programın tamamen yararsız olduğunu ve herhangi bir fayda sağlayamayacağını düşünüyorsanız, o zaman çok yanılıyorsunuz. Yukarıdaki kod, bir port tarayıcının (PortScanner) en basit örneğidir. Böyle bir yardımcı programın özü, belirtilen bağlantı noktasının etkin olup olmadığını ve veri almaya / iletmeye hazır olup olmadığını kontrol etmektir. NetTools Pro'dan PortScanner bu prensibe dayanmaktadır.

    Örnek 2: Soketlerde kısa mesaj gönderme/alma

    (Forma iki adet TButton ve üç adet TEdit yerleştirmeniz gerekmektedir. İlk butona tıkladığınızda OnClick - Button1Click olay işleyicisi çağrılır. Ondan önce TEdit'lerin ilkine host adını girmeniz ve ardından ikincide uzak bilgisayarın portu.Bağlantı kurduktan sonra, üçüncü TEdit'e metin girip ikinci TButton'a basarak metin mesajları gönderebilirsiniz. Bağlantıyı kesmek için, ilk TButton'a tekrar tıklamanız gerekir.Ayrıca bir TListBox eklemeniz gerekir. gelen ve gönderilen mesajları koyacağımız yer.Forma TClientSocket BİLEŞENİNİ YERLEŞTİRMEYİ UNUTMAYIN !}

    prosedür Button1Click(Sender: TObject);
    başlamak
    (Bağlantı zaten kurulmuşsa keseriz.)
    ClientSocket1.Active ise başlayın
    ClientSocket1.Close;
    çıkış; (...ve işleyiciden çıkın)
    son;
    (Host ve Port özelliklerine istenilen değerleri atarız)
    ClientSocket1.Host:= Edit1.Text;
    ClientSocket1.Port:= StrToInt(Edit2.Text);
    (Soket açıp bağlantı kurmaya çalışmak)
    ClientSocket1.Open;
    son;


    başlamak
    (Bağlantı kurulur kurulmaz bir karşılama mesajı göndeririz)
    Socket.SendText('Merhaba!');
    ListBox1.Items.Add('< Hello!′);
    son;

    prosedür ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    başlamak
    (Bir mesaj geldiyse, onu ListBox'a ekleyin)
    ListBox1.Items.Add(′> ′+Socket.ReceiveText);
    son;

    prosedür Button2Click(Sender: TObject);
    başlamak
    (Düğmeye basıldı - üçüncü TEdit'ten metin gönderin)
    ClientSocket1.Socket.SendText(Edit3.Text);
    ListBox1.Items.Add('< ′+Edit3.Text);
    son;

    NOT: Bazı durumlarda (sunucuya bağlı olarak) her mesajdan sonra yeni bir satır göndermek gerekir:
    ClientSocket1.Socket.SendText(Düzenle3.Text+#10);

    Soket akışıyla çalışma

    "Bir prizle başka nasıl çalışabilirsin?" - Siz soruyorsunuz. Doğal olarak, yukarıdaki yöntem en iyi çözüm değildir. Soketlerle çalışmayı organize etmenin birçok yöntemi vardır. Sadece bir tane daha vereceğim - akış boyunca çalışın. Elbette, çoğunuzun akışlarla (akışlarla) değilse de, o zaman dosyalarla - kesin olarak zaten deneyiminiz var. Bilmeyenler için akış, normal bir dosyayla çalışmaya benzer şekilde çalışan bir veri alışverişi kanalıdır. Aşağıdaki örnek, bir iş parçacığının bir soketle çalışacak şekilde nasıl düzenleneceğini gösterir:

    Örnek 3: Soket dişi

    prosedür ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
    var c: Karakter;
    MySocket: TWinSocketStream;
    başlamak
    (Bağlantı kurulur kurulmaz bir thread oluşturup soket ile ilişkilendiriyoruz (60000 - ms cinsinden timeout))
    MySocket:= TWinSocketStream.Create(Socket,60000);
    (WaitForData operatörü, milisaniye cinsinden belirtilen süre boyunca akıştan veri bekler (bu örnekte, 100) ve en az bir bayt veri alınmışsa True, akıştan veri yoksa False döndürür.)
    MySocket.WaitForData(100) yapmazken
    Application.ProcessMessages;
    (Application.ProcessMessages, Windows'un pencerenin gerekli öğelerini yeniden çizmesine izin verir ve diğer programlara zaman tanır. Bu ifade mevcut olmasaydı ve veriler oldukça uzun bir süre gelmezse, sistem biraz "takılırdı".)
    MySocket Okuma(c,1);
    (Read deyimi, akıştan (bu örnekte, 1) belirtilen bayt sayısını belirli bir türdeki belirtilen değişkene (örnekte, Char türündeki c değişkeni) okur. Read'in, ReadBuffer'dan farklı olarak empoze etmediğini unutmayın. alınan bilgi miktarı üzerinde katı kısıtlamalar, yani Okuma, akıştan en fazla n bayt okur (burada n, belirtilen sayıdır. Bu işlev, alınan veri baytlarının sayısını döndürür.)
    MySocket.Write(c,1);
    (Write deyimi, Read deyimine benzer, ancak Write verileri akışa yazar.)
    MySocket.Free;
    (İş parçacığı için ayrılan belleği boşaltmayı unutmayın)
    son;

    NOT: Bir akış kullanmak için ClientType özelliğini ctBlocking olarak ayarladığınızdan emin olun.

    Karmaşık veri gönderme/alma

    Bazen ağ üzerinden yalnızca basit metin mesajlarını değil, aynı zamanda karmaşık yapıları (Pascal'da kayıt yazın) ve hatta dosyaları göndermek gerekir. Ve sonra özel operatörler kullanmanız gerekir. Bunlardan bazıları aşağıda listelenmiştir:

    TClientSocket.Socket(TCustomWinSocket, TClientWinSocket) yöntemleri:
    SendBuf(var Buf; Count: Integer) - Bir yuva üzerinden arabellek gönderme. Yapı (kayıt) veya basit bir Tamsayı olsun, herhangi bir tür arabellek olabilir. Tampon Buf parametresi tarafından belirtilir, ikinci parametre gönderilecek verilerin bayt cinsinden boyutunu belirtmeniz gerekir (Count);
    SendText(const S: string) - Soket aracılığıyla bir metin dizisi gönderme. Bu yöntem örnek 2'de tartışılmıştır (yukarı bakınız);
    SendStream(AStream: TStream) - Belirtilen akışın içeriğini soket üzerinden gönderin. İletilen akış açık olmalıdır. Akış herhangi bir türde olabilir - dosya, RAM vb. Doğrudan akışlarla nasıl çalışılacağını açıklamak bu makalenin kapsamı dışındadır;
    Listelenen tüm yöntemler, Alım yöntemlerine karşılık gelir... Bunların açıklaması, Delphi yardım dosyasında (VCL yardımı) bulunabilir.

    Son olarak, yetkilendirmeyi (sunucuya giriş) nasıl uygulayabileceğinize dair basit bir örnek vermek istiyorum. Bu örnekte parola açık metin olarak gönderilmiştir, bu nedenle gerçekten güvenli bir oturum açma mekanizması istiyorsanız örnek kaynakta bazı değişiklikler yapmanız gerekecektir. Örnek, bir soket akışıyla çalışırken uygulanır.

    (Bu örnekte, forma iki TEdit daha eklemeniz gerekir - kullanıcı adı ve şifre girmek için Edit3 ve Edit4)

    prosedür ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
    var c: Karakter;
    MySocket: TWinSocketStream;
    giriş,şifre:dize;
    başlamak
    MySocket:= TWinSocketStream.Create(Socket,60000);
    (Sunucunun oturum açma ve parolayı ayırabilmesi için kullanıcı adı ve parolaya yeni bir satır karakteri ekliyoruz.)
    giriş:= Edit3.Text+#10;
    şifre:= Edit4.Text+#10;
    MySocket.Write(login,Length(Edit3.Text)+1);
    MySocket.Write(şifre,Uzunluk(Düzenle4.Text)+1);
    MySocket.WaitForData(100) yapmazken
    Application.ProcessMessages;
    MySocket Okuma(c,1);
    (Burada, sunucu bize, değeri başarılı yetkilendirme onayına karşılık gelen 1 ve bir hata olan 0 olan bir bayt gönderir (bu yalnızca bir örnektir). Ardından gerekli işlemleri gerçekleştiririz (veri alma / gönderme) ve akışı kapatın.)
    MySocket.Free;
    son

    Acemi programcılar (ve Delphi'yi öğrenmeye başladığımda ben) kendilerine şu soruyu soruyorlar: Bu dosyaya ek olarak soket aracılığıyla çok fazla bilgi iletiliyorsa, bir dosya soketler aracılığıyla nasıl aktarılır!? Görünüşe göre sorun o kadar karmaşık değil ama yine de kolay değil ... İnternette uzun bir arama yaptıktan sonra bu konuda tek bir yararlı makale bulamadım. Ben de bu eksikliği gidermeye karar verdim ve bu yazıda bu sorunu çözmeye yardımcı olmaya çalışacağım...

    Dosyaları soketler (istemci ve sunucu) aracılığıyla aktarabilen bir program ve bunun yanı sıra, örneğin bir tür mesaj gibi diğer komutları yazalım! İstemci dosyaları veya komutları alacak ve sunucu bunları gönderecektir. İstemci arabelleğe her şeyi arka arkaya yazarsa, dosyaya ek olarak komutlar da içerecektir ve dosyaların ve komutların hiçbir durumda birleşmediğinden emin olmamız gerekir! Ayrıca, dosya büyükse, aktarırken birkaç pakete bölüneceğini, yani dosyanın bir pakette değil, birkaç pakette gönderileceğini ve OnClientRead olayının olacağını da hesaba katmanız gerekir. birkaç kez aradı ... Ana transfer sorunu bu!

    Komutları dosyadan ayırabilmek için önce istemciye şuna benzer bir şey gönderin: "file#file.txt#16", yani: komut + sınırlayıcı + dosya adı + sınırlayıcı + dosya boyutu.
    Bu komutu aldıktan sonra, müşteri dosya alma moduna geçecek ve dosya boyutu alınan verinin boyutuna eşit olana kadar her şeyi arabelleğe yazacaktır. Bu şekilde müşteri komutları dosyadan ayıracaktır!

    O halde kod yazmaya başlayalım:
    Sunucuyla başlayalım (dosyayı gönderecek):

    Aşağıdaki bileşenleri forma yerleştirin: TServerSocket, TButton, TEdit, TProgressBar ve TStatiusBar. Onları resimde gösterildiği gibi düzenleyin.
    TServerSocket bileşenini ayarlayın, bağlantı noktası (bağlantı noktası): 1001.
    TStatusBar bileşeninin SimplePanel değişkenini true olarak ayarlayın.
    Satıra transfer edilecek dosyanın adı yazılır, TButton butonu ile dosya transfer edilir.

    Öncelikle dosya için global değişkenlere bir arabellek ekleyelim:

    Var Form1: TForm1; MS: TMemoryStream; // Dosya için arabellek

    Şimdi formu oluştururken soketi açık hale getirelim:

    Prosedür TForm1.FormCreate(Sender: TObject); ServerSocket1.Open'ı başlatın; // Soket ucunu aç;

    Uygulama sona erdiğinde, soketi kapatmayı hatırlamanız gerekir:

    Prosedür TForm1.FormDestroy(Sender: TObject); ServerSocket1.Close'u başlatın; // soket ucunu kapatın;

    Düğmeye tıkladığınızda dosyayı gönderin:

    Prosedür TForm1.Button1Click(Sender: TObject); // Dosyayı geçir var Boyut: integer; P: ^Byte; MS'i başlatın:= TMemoryStream.Create; // MS.LoadFromFile(Edit1.Text) dosyası için bir tampon oluşturun; // Dosyayı tampona yükleyin // Dosya hakkında bilgi gönderin (komut # ad # boyut) ServerSocket1.Socket.Connections.SendText("file#"+Edit1.Text+"#"+IntToStr(MS.Size)+" #" ); MS.Pozisyon:= 0; // Taşıyıcıyı dosyanın başına taşı P:= MS.Memory; // Dosyayı "P" değişkenine yükleyin Size:= ServerSocket1.Socket.Connections.SendBuf(P^, MS.Size); // Dosyayı gönder // İlerlemeyi görüntüle ProgressBar1.Position:= Boyut*100 div MS.Boyut; StatusBar1.SimpleText:= "+IntToStr(MS.Size)+" baytından "+IntToStr(Boyut)+" gönderildi"; son;

    TServerSocket bileşeninin OnClientRead olayına aşağıdaki kodu girin:

    Prosedür TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); begin if Socket.ReceiveText = "end" then // İstemci dosyayı aldıysa, o zaman... Begin StatusBar1.SimpleText:= "İstemci dosyayı aldı"; MS Ücretsiz; // arabellek sonunu öldür; son;

    Bu, sunucunun arabelleği yalnızca istemci dosyayı kabul ettikten sonra öldürmesi için gereklidir. Dosyayı aktardıktan hemen sonra arabelleği öldürürseniz, istemcinin tüm dosyayı almak için zamanı olmayacaktır! İstemci dosyayı kabul ettikten sonra, sunucuya dosyanın kabul edildiği anlamına gelen bir "son" komutu gönderir ve sunucu arabelleği öldürür.

    Şimdi sunucumuzun bağlantı hakkında bazı bilgiler göstermesini sağlayalım:
    TServerSocket bileşeninin OnClientConnect olayına aşağıdaki kodu girin:

    Prosedür TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); start StatusBar1.SimpleText:= "Bağlandı"; son;

    Ve OnClientDisconnect olayında şunu ekleyin:

    Prosedür TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); start StatusBar1.SimpleText:= "Bağlantı başarısız"; son;

    Artık sunucu hazır! Şimdi müşteriye geçelim (dosyayı kabul eder), onunla daha fazla yaygara olacaktır:

    Bileşenleri foruma yerleştirin: TClientSocket, iki etiket TLabel, TProgressBar ve TStatusBar.
    TClientSocket bileşenini, port (port): 1001 (sunucu gibi) ve değişken adres (adres): 127.0.0.1 (IP'niz) olarak ayarlayın.
    Metnimizin görülebilmesi için TStatusBar bileşeninin SimplePanel değişkenini true olarak ayarlamayı unutmayın.
    Bir TLabel "e'de dosya adı başka bir dosya boyutunda görüntülenir.
    Buna benzer bir şey almalısın:

    Değişkenleri ve bir prosedürü beyan ederiz. Değişkenleri yaz özel aksi takdirde hiçbir şey işe yaramaz:

    Yazma Prosedürü(Metin: dizi); // arabelleğe veri yazma prosedürü özel ( Özel bildirimler ) İsim: string; // Dosya adı Boyut: integer; // Dosya boyutu Al: boolean; // MS istemci modu: TMemoryStream; // Dosya için arabellek

    Form oluşturma olayında sunucuya bağlanıyoruz ve dosyanın aktarılmasını bekliyoruz:

    Prosedür TForm1.FormCreate(Sender: TObject); startClientSocket1.Open; // Açık soket Alma:= false; // İstemci modu - komut alımı sona erer;

    Uygulama sonlandırıldığında soketi kapatın:

    Prosedür TForm1.FormDestroy(Sender: TObject); startClientSocket1.Close; // soket ucunu kapatın;

    Tıpkı sunucuda olduğu gibi, istemciye bağlantı hakkında bilgi vermesini sağlayacağız:

    Prosedür TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); start StatusBar1.SimpleText:= "Bağlandı"; son; prosedür TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); start StatusBar1.SimpleText:= "Bağlantı başarısız"; son;

    Şimdi kodu Yazma prosedürüne eklememiz gerekiyor. Bu prosedür, alınan verileri bir dosyaya yazmak için gereklidir. Prosedür kodu:

    Prosedür TForm1.Writing(Metin: dizi); MS.Size ise başlayın< Size then // Если принято байт меньше размера файла, то... MS.Write(Text, Length(Text)); // Записываем в буфер // Выводим прогресс закачки файла ProgressBar1.Position:= MS.Size*100 div Size; StatusBar1.SimpleText:= "Принято "+IntToStr(MS.Size)+" из "+IntToStr(Size); if MS.Size = Size then // Если файл принят, то... begin Receive:= false; // Переводим клиента в нормальный режим MS.Position:= 0; // Переводим каретку в начало буфера MS.SaveToFile(Name); // Сохраняем файл ClientSocket1.Socket.SendText("end"); // Посылаем команду "end", то есть файл принят MS.Free; // Убиваем буфер StatusBar1.SimpleText:= "Файл принят"; end; end;

    Şimdi TClientSocket bileşeninin OnClientRead olayına aşağıdaki kodu girin:

    Prosedür TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); varRtext:dize; // Alınan metin başlar Rtext:= Socket.ReceiveText; if Receive o zaman // İstemci dosya alma modundaysa, o zaman... Yazma(RText) // Verileri ara belleğe yaz else // İstemci dosya alma modunda değilse, o zaman... başla if Kopyala( Rtext, 0, Pos ("#", Rtext) -1) = "dosya" sonra // Bu bir dosyaysa, o zaman... başla MS:= TMemoryStream.Create; // Sil(Rtext, 1, Pos("#", Rtext)); dosyası için bir tampon oluşturun. // Dosya adını belirleyin Ad:= Kopyala(Rtext, 0, Pos("#", Rtext) -1); // Dosya adını belirle Sil(Rtext, 1, Pos("#", Rtext)); // Dosya boyutunu belirleyin Size:= StrToInt(Copy(Rtext, 0, Pos("#", Rtext) -1)); // Dosya boyutunu belirle Sil(Rtext, 1, Pos("#", Rtext)); // Son ayırıcıyı kaldırın Label1.Caption:= "Dosya boyutu: "+IntToStr(Size)+" bayt"; // Dosya boyutunu yazdır Label2.Caption:= "Dosya adı: "+Ad; // Dosya adını yazdır Al:= true; // Sunucuyu dosya alma moduna geçir Yazma(RText); // Arabellek ucuna veri yaz; son; son;

    Bu nedenle, dosya büyükse ve OnClientRead olayı bir kez değil, birkaç kez çağrılacaksa, istemci dosya alma modundaysa arabelleğe veri yazacaktır, değilse, istemci belirleyecektir. alınan komut ve eğer bu bir dosya ise, o zaman dosya alma moduna geçecektir. Bir şey anlamadıysanız, program kodunu okuyun, oradaki her şeyin yorumunu bir nedenle kaldırdım :-)

    Tamam, şimdi her şey bitti...
    İstemci ve sunucu - hazır! Önce sunucuyu, ardından istemciyi başlatın ve birkaç megabayt boyutunda dosyaları aktarmayı deneyin :-) Ağ üzerinden 10-12 MB dosyaları sorunsuz gönderdim.

    Programlamada iyi şanslar!

    Bu makale, Delphi bileşenlerinin temel özelliklerini ve işlevlerini tartışacaktır: TClientSocket ve TServerSocket - TCP\IP protokolünü kullanan bir ağ ile çalışmak için kullanılır.

    Dikkat! Delphi'nin 6.0'dan daha yüksek bir sürümünü kullanıyorsanız, önce Sockets Components'ı kurmalısınız, Delphi'nin tüm sürümlerinde bu şu şekilde yapılır:

    • Paketleri Kur… iletişim kutusuna gidin: (Ana menü) Bileşen -> Paketleri Kur;
    • Ekle… düğmesine tıklayın, ardından Delphi'nizin Bin klasörünü bulduk (örn.: C:\Program Files\Borland\Delphi 7\bin , veya C:\Program Files\Embarcadero\RAD Studio\7.0\Bin);
    • Bulunan Bin klasöründe zaten bir dosya arıyoruz dcl yuvaları [sayılar burada].bpl, Tamam'ı tıklayın;
    • Mutluyuz, çünkü artık İnternet sekmesinin bileşenler paneli sekmesinde TServerSocket ve TClientSocket adlı iki harika bileşenimiz var.

    Herhangi bir ağ uygulaması geliştirirken, geliştirme genellikle her zaman sunucudan başlar (elbette, bir ekibiniz varsa, ön uç tasarımcılar istemci üzerinde çalışmaya başlayabilir). Şaşırtıcı bir şekilde, sunucuyu uygulamak için TServerSocket kullanmanız gerekir.

    Temel özellikler:

    • Aktif– boole tipi alan, true olarak ayarlandığında – sunucu başlatılır, hem belirli değerler atanarak hem de ServerSocket1.Open (… Active:=true;) veya ServerSocket1.Close (… Active:=false) çağrılarak kullanılabilir fonksiyonlar.
    • liman- sunucunun dinleyeceği (istemcileri alacağı) bağlantı noktası, aralık içindeki sistemdeki diğer sunucular tarafından kullanılmayan herhangi bir değer tamsayı.

    Ana olaylar:

    • Dinle- sunucu dinleme moduna ayarlandığında çağrılır, sunucunun gerçek başlangıç ​​zamanını belirlememiz gerektiğinde kullanılabilir.
    • OnClientRead– müşteriden veri alma anında çağrılır.
    • OnClientError
    • OnClientConnect'te- Sunucuya yeni bir müşteri katıldığında çağrılır.
    • OnClientDisconnect- olayın tersi olay, OnClientConnect'te

    her olay işlevinin bir özniteliği vardır Soket: TCustomWinSocket, şu anda çalışmakta olduğumuz soket nesnesine bir işaretçi iletilir, eğer istemciyle olaya neden olan bir şeyi yanıtlamamız veya bir şey yapmamız gerekirse, kullandığımız diğer tüm durumlarda bu belirli nesneyi kullanmamız gerekir. ServerSocket1.Socket, durum istemci bileşeniyle benzerdir.

    Salt okunur özellikler ve işlevler:

    • – etkin bağlantıların sayısını döndürür.
    • ServerSocket1.Socket.Connections– TCustomWinSocket türünde bir nesne dizisi, istemcilerle ilişkili tüm nesnelerin dizisi, dizin sayısı 0'dan başlar, dizinin uzunluğu şuna eşittir: ServerSocket1.Socket.ActiveConnections.
    • ServerSocket1.Socket.Connections dizisinin öğelerine ve sunucu olay işlevine iletilen Socket özniteliğine uygulanan işlevler ve özellikler:
    • Socket.LocalHost
    • Socket.LocalAddress– sunucunun IP'sini döndürür.
    • Socket.RemoteHost
    • Socket.RemoteAddress– müşterinin IP'sini döndürür.
    • Socket.ReceiveText- müşteriden alınan bir metin mesajını döndürür, ardından arabelleği temizler, 1 alım için yalnızca 1 kez kullanılabilir.
    • Socket.SendText(Metin)– istemciye Metin türünde bir metin mesajı gönderir sicim.

    TClientSocket bileşeni için her şey hemen hemen aynı, sadece tam tersi + sunucu ve istemci arasındaki ana görsel fark, sistemdeki sunucu 1'e 1 port değeri başlatılabilir, yalnızca RAM sizi sayı olarak sınırlar. müşteriler.

    Temel özellikler:

    • Aktif– boole tipi alan, true olarak ayarlandığında – istemci sunucuya bağlanmaya çalışır, hem belirli değerler atayarak hem de ClientSocket1.Open (… Active:=true;) veya ClientSocket1.Close (… Active) çağrılarak kullanılabilir :=yanlış) işlevler .
    • liman– istemcinin sunucuya bağlanabileceği bağlantı noktası, aralık içindeki herhangi bir değer tamsayı.
    • adres– Sunucu türünün IPv4 adresi sicim istemcinin bağlanacağı model 255.255.255.255.

    Ana olaylar:

    • Okumada– kuzeyden veri alındığında çağrılır.
    • Hata Üzerine- Veri aktarımında bir hata oluştuğunda çağrılır.
    • Bağlanıyor- İstemci sunucuya bağlandığında çağrılır.
    • Bağlantı Kesildiğinde- olayın tersi olay, Bağlanıyor, istemcinin sunucuyla bağlantısının kesilmesi sırasında çağrılır.

    Salt okunur özellikler ve işlevler:

    • ClientSocket1.Socket.SendText() sicim
    • Socket.LocalHost– ağdaki istemcinin adını döndürür.
    • Socket.LocalAddress– müşterinin IP'sini döndürür.
    • Socket.RemoteHost– ağdaki sunucunun adını döndürür.
    • Socket.RemoteAddress– sunucunun IP'sini döndürür.
    • Socket.ReceiveText– sunucudan alınan bir metin mesajını döndürür, ardından arabelleği temizler, 1 alım için yalnızca 1 kez kullanılabilir.
    • Socket.SendText(Metin)– sunucuya Metin türünde bir metin mesajı gönderir sicim.

    Sağlanan bilgiler, teknik gereksinimleri karşılayan küçük bir sunucu sohbeti gerçekleştirmek için yeterlidir: internet_sockets.doc (Word Doc 97-2003, 26.5 Kb).

    Bu yazı 10 Ekim 2010 Pazar 01:24 tarihinde yazıldı. Makaleye yapılan yorumların güncellemelerine abone olabilirsiniz -. Yapabilirsiniz


    giriiş


    Bu makale, Borland Delphi'de ("yuvalar" - soket tabanlı istemci/sunucu uygulamaları) oluşturmakla ilgilidir. yuvalar). Yuvalarla ilgili önceki makalenin aksine, burada sunucu uygulamalarının oluşturulmasını inceleyeceğiz.

    Hemen belirtilmelidir ki, ayrı istemci ve sunucu uygulamalarının bir arada bulunması için birkaç bilgisayara sahip olmak gerekli değildir. Aynı anda hem sunucuyu hem de istemciyi çalıştırabileceğiniz tek bir sunucuya sahip olmanız yeterlidir. Bu durumda, bağlanmak istediğiniz bilgisayarın adı olarak ana bilgisayar adını kullanmanız gerekir. yerel ana bilgisayar veya IP adresi - 127.0.0.1 .

    Öyleyse teori ile başlayalım. Eğer sadık bir uygulayıcıysanız (ve herhangi bir algoritmayı gözünüzle göremiyorsanız), o zaman bu bölümü atlamalısınız.

    Soket sunucusu algoritması


    Bir soket sunucusu ne yapar?.. Nasıl çalışır?.. Soket protokolüne dayalı bir sunucu, aynı anda birçok istemciye hizmet vermenizi sağlar. Ayrıca, sayıları için kendiniz bir sınır belirleyebilirsiniz (veya varsayılan olarak yapıldığı gibi bu sınırı tamamen kaldırabilirsiniz). Sunucu, bağlı her istemci için, istemciyle veri alışverişi yapabileceğiniz ayrı bir yuva açar. Ayrıca her bağlantı için ayrı bir işlem (Thread) oluşturmak da harika bir çözümdür.

    Aşağıda, bir soket sunucusunun Delphi uygulamalarında nasıl çalıştığına bir örnek verilmiştir:

    Şemayı daha ayrıntılı olarak inceleyelim:

    • Port ve ServerType'ta özellikleri tanımlama - İstemcilerin sunucuya normal şekilde bağlanabilmeleri için, sunucu tarafından kullanılan bağlantı noktasının, istemci tarafından kullanılan bağlantı noktasıyla tam olarak eşleşmesi gerekir (veya tam tersi). ServerType özelliği, bağlantı türünü belirler (ayrıntılar için aşağıya bakın);
    • soket açıklığı - Bir soket ve belirtilen port açma. Burada, istemcilerin bağlanmasını beklemenin otomatik olarak başlatılması gerçekleştirilir ( Dinlemek);
    • Bir müşteriyi bağlama ve onunla veri alışverişi yapma - burada müşteri bağlanır ve onunla veri alışverişi yapılır. Bu aşama hakkında daha fazla bilgiyi bu makalenin ilerleyen kısımlarında ve soketlerle ilgili makalede (istemci tarafı) öğrenebilirsiniz;
    • Bir istemciyi devre dışı bırakma - Burada istemcinin bağlantısı kesilir ve sunucuya olan soket bağlantısı kapatılır;
    • Sunucuyu ve soketi kapatma - Yöneticinin komutuyla sunucu, tüm açık soket kanallarını kapatarak ve istemci bağlantılarını beklemeyi durdurarak işini sonlandırır.

    3-4 noktalarının birçok kez tekrarlandığına dikkat edilmelidir, yani. bu öğeler her yeni istemci bağlantısı için yürütülür.

    Not : Şu anda Delphi'deki yuvalarla ilgili çok az belge var, bu nedenle bu konuyu olabildiğince derinlemesine incelemek istiyorsanız, Unix/Linux sistemleriyle ilgili literatüre ve elektronik belgelere bakmanızı tavsiye ederim - orada Çok Soketlerle çalışma teorisi iyi tanımlanmıştır. Ek olarak, bu işletim sistemleri için pek çok soket uygulaması örneği vardır (ama çoğunlukla C/C++ ve Perl'de).

    TServerSocket bileşeninin kısa açıklaması


    Burada tanışacağız ana bileşenin özellikleri, yöntemleri ve olayları TServerSocket.

    Özellikler

    Priz - açık soket kanallarına erişiminiz olan TServerWinSocket sınıfı. Sonra, bu özelliği daha ayrıntılı olarak ele alacağız, çünkü. aslında en önemlilerinden biridir. Tip: TServerWinSocket ;
    sunucu tipi - sunucu tipi. İki değerden birini alabilir: stNonBlocking- istemci soketleri ile senkronize çalışma. Bu tür bir sunucuyla, olaylar aracılığıyla müşterilerle çalışabilirsiniz. OnClientRead Ve OnClientWrite'da. stThreadBlocking- eşzamansız tür. Her istemci soket kanalı için ayrı bir işlem (Thread) oluşturulur. Tip: TSunucu Türü ;
    ThreadCacheSize - sunucu tarafından önbelleğe alınacak istemci işlemlerinin (Thread) sayısı. Burada sunucunuzdaki yüke bağlı olarak ortalama değeri seçmeniz gerekiyor. Önbelleğe alma, her seferinde ayrı bir işlem oluşturmamak ve kapalı soketi öldürmemek, daha sonra kullanıma bırakmak için gerçekleşir. Tip: tamsayı ;
    Aktif - sunucunun şu anda aktif olup olmadığının bir göstergesi. Değeri bu aslında Doğru sunucunun çalıştığını ve istemcileri almaya hazır olduğunu gösterir ve YANLIŞ- sunucu kapatıldı. Sunucuyu başlatmak için bu özelliği şu şekilde ayarlamanız yeterlidir: Doğru. Tip: boole ;
    liman - istemcilerle bağlantı kurmak için bağlantı noktası numarası. Sunucu ve istemcilerdeki bağlantı noktası aynı olmalıdır. 1025 ile 65535 arasındaki değerler şu şekilde önerilir: 1'den 1024'e kadar - sistem tarafından kullanılabilir. Tip: tamsayı ;
    Hizmet - hizmeti tanımlayan bir dize ( ftp, http, pop, vb.) kimin portunun kullanılacağı. Bu, bağlantı noktası numaralarını çeşitli standart protokollerle eşleştirmek için bir tür referans kitabıdır. Tip: sicim ;

    açık - Sunucuyu başlatır. Temel olarak, bu komut bir değer atamakla aynıdır. Doğru mülk Aktif;
    kapalı - Sunucuyu durdurur. Temel olarak, bu komut bir değer atamakla aynıdır. YANLIŞ mülk Aktif.

    OnClientConnect'te - bir istemci bir soket bağlantısı kurduğunda ve sunucudan bir yanıt beklediğinde meydana gelir ( Kabul Edildiğinde);
    OnClientDisconnect - istemcinin soket kanalıyla bağlantısı kesildiğinde oluşur;
    OnClientError - geçerli işlem başarısız olduğunda oluşur, örn. Bir hata oluştu;
    OnClientRead - İstemci sunucuya bazı veriler gönderdiğinde gerçekleşir. Bu verilere, geçirilen parametre aracılığıyla erişilebilir. Soket: TCustomWinSocket;
    OnClientWrite'da - sunucu soketteki istemciye veri gönderebildiğinde oluşur;
    OnGetSocket'ta - bu olayın işleyicisinde parametreyi düzenleyebilirsiniz İstemci Soketi;
    OnGetThread'te - bu olayın işleyicisinde, parametreyi ayarlayarak her bir müşteri kanalı için benzersiz bir süreç (Konu) tanımlayabilirsiniz. Soket Konusu istenen alt görev TServerClientThread;
    OnThreadStart'ta , OnThreadEnd'de - sırasıyla bir alt görev (işlem, İş Parçacığı) başladığında veya durduğunda gerçekleşir;
    Kabul Edildiğinde - sunucu bir istemciyi kabul ettiğinde veya bir bağlantıyı reddettiğinde gerçekleşir;
    Dinle - Sunucu, istemcilerin bağlanmasını bekleme moduna girdiğinde gerçekleşir.


    TServerSocket.Socket(TServerWinSocket)


    Peki bir sunucu bir istemciye nasıl veri gönderebilir? Peki ya veri almak? Temel olarak, olaylar üzerinde çalışıyorsanız OnClientRead Ve OnClientWrite'da, ardından client ile ClientSocket (TCustomWinSocket) parametresi aracılığıyla iletişim kurabilirsiniz. İstemci soketleri hakkındaki makalede bu sınıfla çalışma hakkında bilgi edinebilirsiniz. bu sınıf aracılığıyla veri göndermek/göndermek benzerdir - yöntemler (Send/Receive)(Text,Buffer,Stream). Ayrıca TServerSocket.Socket ile çalışırken. Ancak, beri Bir sunucu düşündüğümüz için, bazı yararlı özellikler ve yöntemler vurgulanmalıdır:

    • Aktif Bağlantılar (tamsayı) - bağlı müşteri sayısı;
    • ActiveThreads (tamsayı) çalışan işlemlerin sayısıdır;
    • Bağlantılar (sıralamak), her bağlı istemci için ayrı TClientWinSocket sınıflarından oluşan bir dizidir. Örneğin, bu komut:
      ServerSocket1.Socket.Connections.SendText("Merhaba!");
      ilk bağlanan istemciye bir "Merhaba!" mesajı gönderir. Bu dizinin öğeleriyle çalışmaya yönelik komutlar da (Gönder/Al)(Metin,Buffer, Akış);
    • Boşta Konular (tamsayı) ücretsiz işlemlerin sayısıdır. Bu tür işlemler sunucu tarafından önbelleğe alınır (bkz. ThreadCacheSize);
    • yerel adres, yerel ana bilgisayar, yerel bağlantı noktası- sırasıyla - yerel IP adresi, ana bilgisayar adı, bağlantı noktası;
    • uzak adres, uzak ana bilgisayar, uzak bağlantı noktası- sırasıyla - uzak IP adresi, ana bilgisayar adı, bağlantı noktası;
    • Yöntemler kilit Ve Kilidini aç- Sırasıyla, bir soketin bloke edilmesi ve bloke edilmesinin kaldırılması.

    Uygulama ve örnekler


    Şimdi belirli bir örnekle yukarıdakilere bakalım. Hazır kaynakları tıklayarak indirebilirsiniz.

    Öyleyse, TServerSocket ile çalışmanın çok iyi bir örneğine bakalım (bu örnek, bu bileşeni öğrenmek için en görsel yardımcıdır). Aşağıdaki kaynaklar, tüm önemli sunucu olaylarının günlüğe kaydedilmesini ve ayrıca kısa mesaj alma ve gönderme becerisini gösterir:

    örnek 1 Sunucunun çalışmasını günlüğe kaydetme ve inceleme, soketler aracılığıyla mesaj gönderme / alma

    (... İşte dosya başlığı ve TForm1 formunun ve onun Form1 örneğinin tanımı gelir)
    (Tam kaynağa bakın)
    prosedür TForm1.Button1Click(Sender: TObject); başlamak (Portu tanımlıyoruz ve sunucuyu başlatıyoruz) ServerSocket1.Port:= 1025; (Insert yöntemi, diziye belirtilen konumda bir dize ekler) Memo2.Lines.Insert(0,"Sunucu başlatılıyor"); ServerSocket1.Open; son; prosedür TForm1.Button2Click(Sender: TObject); başlamak (Sunucuyu durdurun) ServerSocket1.Active:= Yanlış; Memo2.Lines.Insert(0,"Sunucu durduruldu"); son; prosedür TForm1.ServerSocket1Listen(Sender: TObject; Socket: TCustomWinSocket); başlamak (Burada sunucu istemciler için soketi "dinler") Memo2.Lines.Insert(0,"Portta dinleme "+IntToStr(ServerSocket1.Port)); son; prosedür TForm1.ServerSocket1Accept(Sender: TObject; Socket: TCustomWinSocket); başlamak (Burada sunucu istemciyi kabul eder) Memo2.Lines.Insert(0,"İstemci bağlantısı kabul edildi"); son; prosedür TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); başlamak (Burada müşteri bağlanır) Memo2.Lines.Insert(0,"İstemci bağlandı"); son; prosedür TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); başlamak (Burada müşteri bağlantıyı keser) Memo2.Lines.Insert(0,"İstemci bağlantısı kesildi"); son; prosedür TForm1.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); başlamak (Bir hata oluştu - kodunu yazdırın) Memo2.Lines.Insert(0,"Client error. Code = "+IntToStr(ErrorCode)); son; prosedür TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); başlamak (İstemciden bir mesaj alındı ​​- bunu Not1'de gösteriyoruz) Memo2.Lines.Insert(0,"İstemciden mesaj alındı"); Memo1.Lines.Insert(0,"> "+Socket.ReceiveText); son; prosedür TForm1.ServerSocket1ClientWrite(Sender: TObject; Socket: TCustomWinSocket); başlamak (Artık sokete veri gönderebilirsiniz) Memo2.Lines.Insert(0,"Artık sokete yazılabilir"); son; prosedür TForm1.ServerSocket1GetSocket(Sender: TObject; Socket: Integer; var ClientSocket: TServerClientWinSocket); Begin Memo2.Lines.Insert(0,"Get socket"); son; prosedür TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); Begin Memo2.Lines.Insert(0,"Get Thread"); son; prosedür TForm1.ServerSocket1ThreadEnd(Gönderen: TObject; Konu: TServerClientThread); Begin Memo2.Lines.Insert(0,"Konu sonu"); son; prosedür TForm1.ServerSocket1ThreadStart(Gönderen: TObject; Konu: TServerClientThread); Begin Memo2.Lines.Insert(0,"Konu başlangıcı"); son; prosedür TForm1.Button3Click(Sender: TObject); var i: Tamsayı; başlamak (TÜM istemcilere Edit1'den bir mesaj gönderin) i:= 0'dan ServerSocket1.Socket.ActiveConnections-1'e ServerSocket1.Socket.Connections[i].SendText(Edit1.Text) başlar; son; Not1.Satırlar.Ekle(0,"

    TServerSocket (ve sadece soketler) ile çalışma teknikleri


    Her müşteri için benzersiz verilerin saklanması.


    Elbette, sunucunuz birçok istemciye hizmet verecekse, her istemci için bazı bilgileri (isim vb.) Saklamanız ve bu bilgileri bu istemcinin soketine bağlamanız gerekecektir. Bazı durumlarda, tüm bunları manuel olarak yapmak (bir soket tutamacına, istemci dizilerine vb. Bağlamak) çok uygun değildir. Bu nedenle, her soket için özel bir özellik vardır - Veri. Aslında, Data yalnızca bir işaretçidir. Bu nedenle, müşteri verilerini bu özelliğe yazarken dikkatli olun ve işaretçilerle çalışma kurallarına uyun (bellek tahsisi, tür çıkarımı vb.)!

    Bir soket üzerinden dosya gönderme.


    Burada bir soket üzerinden dosya göndermeye bakacağız (JINX'in isteği üzerine) :-). Peki bir soket üzerinden nasıl dosya gönderirsiniz? Çok basit! Bu dosyayı bir dosya akışı (TFileStream) olarak açmanız ve soket (SendStream) aracılığıyla göndermeniz yeterlidir! Buna bir örnekle bakalım:

    Unutulmamalıdır ki, yöntem gönderi akışı yalnızca sunucu tarafından değil, istemci tarafından da kullanılır ( ClientSocket1.Socket.SendStream(srcfile))

    İletim sırasında neden birkaç blok bir araya getirilebilir?


    Bu aynı zamanda JINX tarafından da talep edilmektedir :-). Bunun için ona çok teşekkürler! Bu nedenle, öncelikle, soket aracılığıyla gönderilen verilerin yalnızca bir bloğa birleştirilemeyeceği, aynı zamanda birkaç bloğa da ayrılabileceği belirtilmelidir. Gerçek şu ki, soket normal bir akıştır, ancak örneğin bir dosya akışının (TFileStream) aksine, verileri daha yavaş aktarır (anlıyorsunuz - ağ, sınırlı trafik vb.). Bu nedenle iki komut:
    ServerSocket1.Socket.Connections.SendText("Merhaba, ");
    ServerSocket1.Socket.Connections.SendText("dünya!");
    bir komutla tamamen aynıdır:
    ServerSocket1.Socket.Connections.SendText("Merhaba dünya!");

    İşte bu nedenle, soket üzerinden diyelim ki 100 Kb'lik bir dosya gönderirseniz, bu bloğu gönderdiğiniz kişi, trafiğe ve hat yüküne bağlı olarak boyutları olan birkaç blok alacaktır. Üstelik boyutların aynı olması da gerekmiyor. Bir dosyayı veya başka herhangi bir büyük veriyi almak için veri blokları almanız ve ardından bunları bir bütün halinde birleştirmeniz (ve örneğin bir dosyaya kaydetmeniz) gerekir. Bu soruna mükemmel bir çözüm, aynı dosya akışıdır - TFileStream (veya bellekteki bir akış - TMemoryStream). Evrensel yöntemi kullanarak OnRead (OnClientRead) olayı aracılığıyla soketten veri parçacıkları alabilirsiniz. AlımBuf. Ortaya çıkan bloğun boyutunu yöntemi kullanarak belirleyebilirsiniz. Alma Uzunluğu. Bir soket akışı da kullanabilirsiniz (TClientSocket makalesine bakın). Ve işte küçük bir örnek (yaklaşık):

    Bir soket nasıl izlenir


    Bu konu karmaşıktır ve uzun bir değerlendirme gerektirir. Şimdilik, yalnızca programınız tarafından oluşturulan soketi her zaman izleyebileceğinizi not edeceğim :-). Soketlerin (Windows'taki çoğu nesne gibi) Handle özelliğinde yazılmış kendi tanıtıcıları (tutma yerleri) vardır. Böylece, bu tanımlayıcıyı öğrendikten sonra, herhangi bir soketi (başka birinin programı tarafından oluşturulanlar bile) özgürce kontrol edebilirsiniz! Ancak, başka birinin soketini izlemek için büyük olasılıkla WinAPI Sockets işlevlerini kullanmanız gerekecektir.


    Bu makale, Delphi'de TServerSocket bileşeniyle çalışmanın temel püf noktalarını ve yuvalar üzerinden iletişim kurmak için birkaç genel hileyi göstermektedir. Herhangi bir sorunuz varsa - bana e-posta ile gönderin: [e-posta korumalı] ve daha da iyisi - bu sitenin forumuna yazın (Delphi. Genel sorular), böylece diğer kullanıcılar sorunuzu görebilir ve yanıtlamaya çalışabilir!

    Karik Nikolay ( nitro). Moskova bölgesi, Zhukovski