Berbicara tentang penerapan “flow” pada pemrograman Delphi
Chen Jingtao
Apa itu aliran? Stream, sederhananya, adalah alat pengolah data abstrak berbasis berorientasi objek. Dalam aliran, beberapa operasi dasar untuk memproses data didefinisikan, seperti membaca data, menulis data, dll. Pemrogram melakukan semua operasi pada aliran tanpa mempedulikan arah aliran data sebenarnya di ujung aliran yang lain. Streaming tidak hanya dapat memproses file, tetapi juga memori dinamis, data jaringan, dan bentuk data lainnya. Jika Anda sangat mahir dalam operasi aliran dan menggunakan kenyamanan aliran dalam program Anda, efisiensi penulisan program akan sangat meningkat.
Di bawah ini, penulis menggunakan empat contoh: enkripsi file EXE, kartu ucapan elektronik, OICQ buatan sendiri dan transmisi layar jaringan untuk menggambarkan penggunaan "stream" dalam pemrograman Delphi. Beberapa teknik dalam contoh ini dulunya merupakan rahasia banyak perangkat lunak dan tidak dibuka untuk umum. Sekarang semua orang dapat langsung mengutip kodenya secara gratis.
“Gedung-gedung tinggi menjulang dari permukaan tanah.” Sebelum menganalisis contoh-contohnya, mari kita pahami dulu konsep dasar dan fungsi aliran. Baru setelah memahami hal-hal dasar tersebut kita bisa melanjutkan ke langkah berikutnya. Harap pastikan untuk memahami metode dasar ini dengan cermat. Tentu saja, jika Anda sudah familiar dengannya, Anda bisa melewati langkah ini.
1. Konsep dasar dan deklarasi fungsi stream di Delphi
Di Delphi, kelas dasar dari semua objek aliran adalah kelas TStream, yang mendefinisikan properti dan metode umum dari semua aliran.
Properti yang didefinisikan dalam kelas TStream diperkenalkan sebagai berikut:
1. Ukuran: Properti ini mengembalikan ukuran data dalam aliran dalam byte.
2. Posisi: Atribut ini mengontrol posisi penunjuk akses dalam aliran.
Ada empat metode virtual yang ditentukan di Tstream:
1. Baca: Metode ini membaca data dari aliran. Prototipe fungsinya adalah:
Fungsi Baca(var Buffer;Hitung:Longint):Longint;virtual;abstrak;
Parameter Buffer adalah buffer yang ditempatkan ketika data dibaca. Hitungan adalah jumlah byte data yang akan dibaca. Nilai yang dikembalikan dari metode ini adalah jumlah byte sebenarnya yang dibaca, yang bisa kurang dari atau sama dengan nilai yang ditentukan Menghitung.
2. Tulis: Metode ini menulis data ke dalam aliran. Prototipe fungsinya adalah:
Fungsi Tulis(var Buffer;Hitungan:Longint):Longint;virtual;abstrak;
Parameter Buffer adalah buffer data yang akan ditulis ke dalam aliran, Hitung adalah panjang data dalam byte, dan nilai kembalian metode ini adalah jumlah byte yang sebenarnya ditulis ke dalam aliran.
3. Carilah: Metode ini mengimplementasikan pergerakan penunjuk baca di aliran. Prototipe fungsinya adalah:
Fungsi Mencari(Offset:Longint;Asal:Word):Longint;virtual;abstrak;
Parameter Offset adalah jumlah byte offset, dan parameter Asal menunjukkan arti sebenarnya dari Offset.
soFromBeginning:Offset adalah posisi penunjuk dari awal data setelah pergerakan. Pada saat ini Offset harus lebih besar atau sama dengan nol.
soFromCurrent:Offset adalah posisi relatif penunjuk setelah pergerakan dan penunjuk saat ini.
soFromEnd:Offset adalah posisi penunjuk dari akhir data setelah pergerakan. Pada saat ini Offset harus kurang dari atau sama dengan nol. Nilai kembalian metode ini adalah posisi penunjuk setelah pergerakan.
4. Setsize: Metode ini mengubah ukuran data. Prototipe fungsinya adalah:
Fungsi Setsize(Ukuran Baru:Longint);virtual;
Selain itu, beberapa metode statis juga didefinisikan di kelas TStream:
1. ReadBuffer: Fungsi metode ini adalah membaca data dari posisi saat ini di aliran. Prototipe fungsinya adalah:
Prosedur ReadBuffer(var Buffer;Hitungan:Longint);
Definisi parameter sama dengan Baca di atas. Catatan: Jika jumlah byte data yang dibaca tidak sama dengan jumlah byte yang perlu dibaca, pengecualian EReadError akan dihasilkan.
2. WriteBuffer: Fungsi metode ini adalah untuk menulis data ke aliran pada posisi saat ini. Prototipe fungsinya adalah:
Prosedur WriteBuffer(var Buffer;Hitungan:Longint);
Definisi parameter sama dengan Tulis di atas. Catatan: Jika jumlah byte data yang ditulis tidak sama dengan jumlah byte yang perlu ditulis, pengecualian EWriteError akan dihasilkan.
3. CopyFrom: Metode ini digunakan untuk menyalin aliran data dari aliran lain. Prototipe fungsinya adalah:
Fungsi CopyFrom(Sumber:TStream;Hitungan:Longint):Longint;
Parameter Sumber adalah aliran yang menyediakan data, dan Hitungan adalah jumlah byte data yang disalin. Ketika Hitungan lebih besar dari 0, CopyFrom menyalin Hitung byte data dari posisi saat ini dari parameter Sumber; ketika Hitungan sama dengan 0, CopyFrom mengatur properti Posisi dari parameter Sumber ke 0, dan kemudian menyalin semua data Sumber. ;
TStream memiliki kelas turunan lainnya, yang paling umum digunakan adalah kelas TFileStream. Untuk menggunakan kelas TFileStream untuk mengakses file, Anda harus membuat instance terlebih dahulu. Pernyataannya adalah sebagai berikut:
konstruktor Buat(const Nama file:string;Mode:Word);
Nama file adalah nama file (termasuk jalur), dan parameter Mode adalah cara membuka file, yang mencakup mode pembukaan file dan mode berbagi.
Modus terbuka:
fmCreate: Buat file dengan nama file yang ditentukan, atau buka file jika sudah ada.
fmOpenRead: Buka file tertentu dalam mode read-only
fmOpenWrite: Buka file tertentu dalam mode tulis saja
fmOpenReadWrite: Membuka file yang ditentukan untuk menulis
Modus berbagi:
fmShareCompat: Mode berbagi kompatibel dengan FCB
fmShareExclusive: Jangan izinkan program lain membuka file dengan cara apa pun
fmShareDenyWrite: Jangan izinkan program lain membuka file untuk ditulis
fmShareDenyRead: Jangan izinkan program lain membuka file dalam mode baca
fmShareDenyNone: Program lain dapat membuka file dengan cara apa pun
TStream juga memiliki kelas turunan, TMemoryStream, yang sangat sering digunakan dalam aplikasi sebenarnya. Ini disebut aliran memori, yang berarti membuat objek aliran di memori. Metode dan fungsi dasarnya sama seperti di atas.
Nah, dengan landasan di atas, kita bisa memulai perjalanan pemrograman kita.
--------------------------------------------------- --------------------------
2. Aplikasi praktis pertama: menggunakan aliran untuk membuat enkripsi file EXE, bundel, file self-extracting dan program instalasi
Pertama mari kita bicara tentang cara membuat enkripsi file EXE.
Prinsip enkripsi file EXE: Membuat dua file, satu digunakan untuk menambahkan sumber daya ke file EXE lainnya, yang disebut program tambahan. File EXE lain yang ditambahkan disebut file header. Fungsi program ini adalah membaca file yang ditambahkan ke dirinya sendiri. Struktur file EXE di Windows relatif rumit, dan beberapa program juga memiliki checksum ketika ditemukan telah diubah, mereka akan mengira bahwa program tersebut terinfeksi virus dan menolak untuk mengeksekusi. Jadi kami menambahkan file tersebut ke program kami sendiri sehingga struktur file asli tidak akan berubah. Mari kita tulis fungsi add terlebih dahulu. Fungsi dari fungsi ini adalah untuk menambahkan file sebagai aliran ke akhir file lain. Fungsinya adalah sebagai berikut:
Fungsi Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
var
Target,Sumber:TFileStream;
Ukuran File Saya: bilangan bulat;
mulai
mencoba
Sumber:=TFileStream.Create(SourceFile,fmOpenRead atau fmShareExclusive);
Target:=TFileStream.Create(TargetFile,fmOpenWrite atau fmShareExclusive);
mencoba
Target.Seek(0,soFromEnd);//Tambahkan sumber daya sampai akhir
Target.CopyFrom(Sumber,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//Hitung ukuran sumber daya dan tuliskan di akhir proses tambahan
Target.WriteBuffer(Ukuran File Saya,ukuran(Ukuran File Saya));
Akhirnya
Target.Gratis;
Sumber.Gratis;
akhir;
kecuali
Hasil:=Salah;
KELUAR;
akhir;
Hasil:=Benar;
akhir;
Dengan landasan di atas, kita akan dengan mudah memahami fungsi ini. Parameter SourceFile adalah file yang akan ditambahkan, dan parameter TargetFile adalah file target yang akan ditambahkan. Misalnya, untuk menambahkan a.exe ke b.exe: Cjt_AddtoFile('a.exe',b.exe'); Jika penambahan berhasil, maka akan mengembalikan True, jika tidak maka akan mengembalikan False.
Berdasarkan fungsi di atas kita dapat menulis fungsi baca sebaliknya:
Fungsi Cjt_LoadFromFile(SourceFile,TargetFile:string):Boolean;
var
Sumber: TFileStream;
Target:TMemoryStream;
Ukuran File Saya: bilangan bulat;
mulai
mencoba
Target:=TMemoryStream.Buat;
Sumber:=TFileStream.Create(SourceFile,fmOpenRead atau fmShareDenyNone);
mencoba
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//Baca ukuran sumber daya
Source.Seek(-MyFileSize,soFromEnd);//Temukan lokasi sumber daya
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//Hapus sumber daya
Target.SaveToFile(TargetFile);//Simpan ke file
Akhirnya
Target.Gratis;
Sumber.Gratis;
akhir;
kecuali
Hasil:=salah;
KELUAR;
akhir;
Hasil:=benar;
akhir;
Parameter SourceFile adalah nama file yang ditambahkan file tersebut, dan parameter TargetFile adalah nama file target yang disimpan setelah file tersebut dikeluarkan. Misalnya, Cjt_LoadFromFile('b.exe','a.txt'); mengeluarkan file dalam b.exe dan menyimpannya sebagai a.txt. Jika ekstraksi berhasil, ia mengembalikan True jika tidak, ia mengembalikan False.
Buka Delphi, buat proyek baru, dan letakkan kontrol Edit Edit1 dan dua Tombol di jendela: Button1 dan Button2. Properti Caption Button masing-masing disetel ke "OK" dan "Cancel". Tulis kode di acara Klik pada Button1:
var S: tali;
mulai
S:=ChangeFileExt(application.ExeName,'.Cjt');
jika Edit1.Teks='790617' lalu
mulai
Cjt_LoadFromFile(Aplikasi.ExeName,S);
{Keluarkan file dan simpan di jalur saat ini dan beri nama "file asli.Cjt"}
Winexec(pchar(S),SW_Show);{Jalankan "file asli.Cjt"}
Aplikasi.Hentikan;{Keluar dari program}
akhir
kalau tidak
Application.MessageBox('Kata Sandi salah, silakan masukkan kembali!', 'Kata Sandi salah', MB_ICONERROR+MB_OK);
Kompilasi program ini dan ganti nama file EXE menjadi head.exe. Buat file teks baru head.rc dengan konten: head exefile head.exe, lalu salin ke direktori BIN Delphi, jalankan perintah Dos Brcc32.exe head.rc, dan file head.res akan dibuat file adalah Simpan file resource yang kita inginkan terlebih dahulu.
File header kita sudah dibuat, mari kita buat program add-innya.
Buat proyek baru dan tempatkan kontrol berikut: properti Edit, Opendialog, dan Caption dari kedua Button1 masing-masing disetel ke "Pilih File" dan "Enkripsi". Tambahkan kalimat di program sumber: {$R head.res} dan salin file head.res ke direktori program saat ini. Dengan cara ini, head.exe yang tadi dikompilasi bersama dengan program.
Tulis kode di acara Cilck Button1:
jika OpenDialog1.Execute lalu Edit1.Text:=OpenDialog1.FileName;
Tulis kode di acara Cilck Button2:
var S:String;
mulai
S:=ExtractFilePath(Edit1.Teks);
jika ExtractRes('exefile','head',S+'head.exe') lalu
jika Cjt_AddtoFile(Edit1.Text,S+'head.exe') lalu
jika DeleteFile(Edit1.Teks) lalu
jika Ganti NamaFile(S+'head.exe',Edit1.Teks) lalu
Application.MessageBox('Enkripsi file berhasil!','Pesan',MB_ICONINFORMATION+MB_OK)
kalau tidak
mulai
jika FileExists(S+'head.exe') maka DeleteFile(S+'head.exe');
Application.MessageBox('Enkripsi file gagal!','Pesan',MB_ICONINFORMATION+MB_OK)
akhir;
akhir;
Diantaranya, ExtractRes adalah fungsi khusus yang digunakan untuk mengekstrak head.exe dari file sumber daya.
Fungsi ExtractRes(ResType, ResName, ResNewName : String):boolean;
var
Perihal : TResourceStream;
mulai
mencoba
Res := TResourceStream.Create(Petunjuk, Ganti Nama, Pchar(ResType));
mencoba
Res.SavetoFile(ResNewName);
Hasil:=benar;
Akhirnya
Res.Gratis;
akhir;
kecuali
Hasil:=salah;
akhir;
akhir;
Catatan: Fungsi kami di atas hanya menambahkan satu file ke akhir file lainnya. Dalam aplikasi sebenarnya, ini dapat diubah untuk menambahkan banyak file, selama alamat offset ditentukan sesuai dengan ukuran dan jumlah sebenarnya. Misalnya, file bundler menambahkan dua atau lebih program ke file header. Prinsip program self-extracting dan installernya sama, tetapi dengan kompresi yang lebih besar. Misalnya kita bisa mereferensikan unit LAH, mengompres alirannya lalu menambahkannya, sehingga file menjadi lebih kecil. Cukup dekompresi sebelum membacanya. Selain itu, contoh enkripsi EXE pada artikel tersebut masih memiliki banyak kekurangan. Misalnya, kata sandinya ditetapkan menjadi "790617", dan setelah mengeluarkan EXE dan menjalankannya, harus dihapus setelah selesai dijalankan, dll. .Pembaca dapat memodifikasinya sendiri.
--------------------------------------------------- -------------------
3. Aplikasi Praktis 2: Menggunakan stream untuk membuat kartu ucapan elektronik yang dapat dieksekusi
Kita sering melihat beberapa perangkat lunak produksi kartu ucapan elektronik yang memungkinkan Anda memilih gambar sendiri, dan kemudian akan menghasilkan file EXE yang dapat dieksekusi untuk Anda. Saat Anda membuka kartu ucapan, gambar akan ditampilkan saat musik diputar. Sekarang kita telah mempelajari operasi aliran, kita juga dapat membuatnya.
Dalam proses penambahan gambar kita bisa langsung menggunakan Cjt_AddtoFile yang sebelumnya, dan yang perlu kita lakukan sekarang adalah bagaimana cara membaca dan menampilkan gambar tersebut. Kita dapat menggunakan Cjt_LoadFromFile sebelumnya untuk membaca gambar terlebih dahulu, menyimpannya sebagai file dan kemudian memuatnya. Namun, ada cara yang lebih sederhana, yaitu langsung membaca aliran file dan menampilkannya dengan alat aliran yang canggih , semuanya menjadi sederhana.
Gambar yang paling populer saat ini adalah format BMP dan format JPG. Sekarang kita akan menulis fungsi membaca dan menampilkan untuk kedua jenis gambar ini.
Fungsi Cjt_BmpLoad(ImgBmp:TImage;SourceFile:String):Boolean;
var
Sumber: TFileStream;
Ukuran File Saya: bilangan bulat;
mulai
Sumber:=TFileStream.Create(SourceFile,fmOpenRead atau fmShareDenyNone);
mencoba
mencoba
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//Baca sumber daya
Source.Seek(-MyFileSize,soFromEnd);//Temukan posisi awal sumber daya
ImgBmp.Picture.Bitmap.LoadFromStream(Sumber);
Akhirnya
Sumber.Gratis;
akhir;
kecuali
Hasil:=Salah;
KELUAR;
akhir;
Hasil:=Benar;
akhir;
Di atas adalah fungsi untuk membaca gambar BMP, dan berikut ini adalah fungsi untuk membaca gambar JPG. Karena menggunakan satuan JPG, maka kalimat: menggunakan jpeg harus ditambahkan ke dalam program.
Fungsi Cjt_JpgLoad(JpgImg:Timage;SourceFile:String):Boolean;
var
Sumber: TFileStream;
Ukuran File Saya: bilangan bulat;
JPG Saya: TJpegImage;
mulai
mencoba
Myjpg:= TJpegImage.Buat;
Sumber:=TFileStream.Create(SourceFile,fmOpenRead atau fmShareDenyNone);
mencoba
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Sumber.ReadBuffer(Ukuran File Saya,ukuran(Ukuran File Saya));
Source.Seek(-MyFileSize,soFromEnd);
Myjpg.LoadFromStream(Sumber);
JpgImg.Picture.Bitmap.Assign(Myjpg);
Akhirnya
Sumber.Gratis;
Myjpg.gratis;
akhir;
kecuali
Hasil:=salah;
KELUAR;
akhir;
Hasil:=benar;
akhir;
Dengan kedua fungsi tersebut, kita dapat membuat program pembacaan. Mari kita ambil gambar BMP sebagai contoh:
Jalankan Delphi, buat proyek baru, dan letakkan kontrol tampilan gambar Image1. Cukup tulis kalimat berikut di jendela Create event:
Cjt_BmpLoad(Gambar1,Aplikasi.ExeName);
Ini adalah file header, dan kemudian kita menggunakan metode sebelumnya untuk menghasilkan file sumber daya head.res.
Sekarang kita bisa mulai membuat program tambahan kita. Seluruh kodenya adalah sebagai berikut:
satuan Unit1;
antarmuka
kegunaan
Windows, Pesan, SysUtils, Kelas, Grafik, Kontrol, Formulir, Dialog,
ExtCtrls, StdCtrls, ExtDlgs;
jenis
TForm1 = kelas(TForm)
Sunting1: TEdit;
Tombol1: Tombol T;
Tombol2: Tombol T;
OpenPictureDialog1: TOpenPictureDialog;
prosedur FormCreate(Pengirim: TObject);
prosedur Button1Click(Pengirim: TObject);
prosedur Button2Click(Pengirim: TObject);
pribadi
Fungsi ExtractRes(ResType, ResName, ResNewName : String):boolean;
Fungsi Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
{Deklarasi pribadi}
publik
{Pernyataan publik}
akhir;
var
Formulir1: TForm1;
pelaksanaan
{$R *.DFM}
Fungsi TForm1.ExtractRes(ResType, ResName, ResNewName : String):boolean;
var
Perihal : TResourceStream;
mulai
mencoba
Res := TResourceStream.Create(Petunjuk, Ganti Nama, Pchar(ResType));
mencoba
Res.SavetoFile(ResNewName);
Hasil:=benar;
Akhirnya
Res.Gratis;
akhir;
kecuali
Hasil:=salah;
akhir;
akhir;
Fungsi TForm1.Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
var
Target,Sumber:TFileStream;
Ukuran File Saya: bilangan bulat;
mulai
mencoba
Sumber:=TFileStream.Create(SourceFile,fmOpenRead atau fmShareExclusive);
Target:=TFileStream.Create(TargetFile,fmOpenWrite atau fmShareExclusive);
mencoba
Target.Seek(0,soFromEnd);//Tambahkan sumber daya sampai akhir
Target.CopyFrom(Sumber,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//Hitung ukuran sumber daya dan tuliskan di akhir proses tambahan
Target.WriteBuffer(Ukuran File Saya,ukuran(Ukuran File Saya));
Akhirnya
Target.Gratis;
Sumber.Gratis;
akhir;
kecuali
Hasil:=Salah;
KELUAR;
akhir;
Hasil:=Benar;
akhir;
prosedur TForm1.FormCreate(Pengirim: TObject);
mulai
Keterangan:='Program demonstrasi Bmp2Exe. Penulis: Chen Jingtao';
Sunting1.Teks:='';
OpenPictureDialog1.DefaultExt := GraphicExtension(TBitmap);
OpenPictureDialog1.Filter := GraphicFilter(TBitmap);
Button1.Caption:='Pilih gambar BMP';
Button2.Caption:='Hasilkan EXE';
akhir;
prosedur TForm1.Button1Click(Pengirim: TObject);
mulai
jika OpenPictureDialog1.Jalankan lalu
Edit1.Teks:=OpenPictureDialog1.NamaFile;
akhir;
prosedur TForm1.Button2Click(Pengirim: TObject);
var
Suhu Kepala:String;
mulai
jika Bukan FileExists(Edit1.Teks) maka
mulai
Application.MessageBox('File gambar BMP tidak ada, silakan pilih lagi!','Pesan',MB_ICONINFORMATION+MB_OK)
KELUAR;
akhir;
HeadTemp:=ChangeFileExt(Edit1.Teks,'.exe');
jika ExtractRes('exefile','head',HeadTemp) lalu
jika Cjt_AddtoFile(Edit1.Text,HeadTemp) lalu
Application.MessageBox('File EXE berhasil dibuat!','Pesan',MB_ICONINFORMATION+MB_OK)
kalau tidak
mulai
jika FileExists(HeadTemp) maka DeleteFile(HeadTemp);
Application.MessageBox('Pembuatan file EXE gagal!','Pesan',MB_ICONINFORMATION+MB_OK)
akhir;
akhir;
akhir.
Bagaimana dengan itu? Sungguh menakjubkan :) Jadikan antarmuka program lebih indah dan tambahkan beberapa fungsi, dan Anda akan menemukan bahwa itu tidak kalah dengan perangkat lunak yang memerlukan registrasi.
--------------------------------------------------- --------------------------
Penerapan praktis ketiga: Gunakan aliran untuk membuat OICQ Anda sendiri
OICQ adalah perangkat lunak komunikasi online real-time yang dikembangkan oleh Shenzhen Tencent Company dan memiliki basis pengguna yang besar di Tiongkok. Namun, OICQ harus terhubung ke Internet dan login ke server Tencent sebelum dapat digunakan. Jadi kita bisa menulisnya sendiri dan menggunakannya di jaringan lokal.
OICQ menggunakan protokol UDP yang merupakan protokol connectionless, yaitu pihak yang berkomunikasi dapat mengirimkan informasi tanpa harus menjalin sambungan, sehingga efisiensinya relatif tinggi. Kontrol NMUDP dari FastNEt yang disertakan dengan Delphi sendiri adalah kontrol datagram pengguna dari protokol UDP. Namun perlu diperhatikan jika menggunakan kontrol ini, Anda harus keluar dari program sebelum mematikan komputer, karena kontrol TNMXXX terdapat BUG. ThreadTimer yang digunakan oleh PowerSocket, dasar dari semua kontrol nm, menggunakan jendela tersembunyi (kelas TmrWindowClass) untuk mengatasi kekurangan.
Apa yang salah:
Psock::TThreadTimer::WndProc(var pesan:TMessage)
jika msg.message=WM_TIMER maka
Dia menanganinya sendiri
pesan.hasil:=0
kalau tidak
pesan.hasil:=DefWindowProc(0,....)
akhir
Masalahnya adalah ketika memanggil DefWindowProc, parameter HWND yang dikirimkan sebenarnya adalah konstanta 0, jadi sebenarnya DefWindowProc tidak dapat berfungsi. Panggilan ke pesan input apa pun menghasilkan 0, termasuk sesi WM_QUERYEND, sehingga windows tidak dapat keluar. Karena panggilan DefWindowProc yang tidak normal, sebenarnya, kecuali WM_TIMER, pesan lain yang diproses oleh DefWindowProc tidak valid.
Solusinya ada di PSock.pas
Dalam TThreadTimer.Wndproc
Hasil := DefWindowProc( 0, Pesan, WPARAM, LPARAM );
Ubah menjadi:
Hasil := DefWindowProc( FWindowHandle, Msg, WPARAM, LPARAM );
OICQ versi awal tingkat rendah juga mengalami masalah ini. Jika OICQ tidak dimatikan, layar akan berkedip sejenak dan kemudian kembali ketika komputer dimatikan.
Oke, tanpa basa-basi lagi, mari kita tulis OICQ kita. Ini sebenarnya adalah contoh yang disertakan dengan Delphi :)
Buat proyek baru, seret kontrol NMUDP dari panel FASTNET ke jendela, lalu tempatkan tiga EDIT bernama Editip, EditPort, EditMyTxt, tiga tombol BtSend, BtClear, BtSave, sebuah MEMOMemoReceive, sebuah SaveDialog dan sebuah status bar1. Ketika pengguna mengklik BtSend, objek aliran memori dibuat, informasi teks yang akan dikirim ditulis ke dalam aliran memori, dan kemudian NMUDP mengirimkan aliran tersebut keluar. Ketika NMUDP menerima data, event DataReceived dipicu. Di sini kita mengubah aliran yang diterima menjadi informasi karakter dan kemudian menampilkannya.
Catatan: Ingatlah untuk melepaskan (Gratis) semua objek aliran setelah dibuat dan digunakan. Faktanya, destruktornya harus Hancurkan. Namun, jika pembuatan aliran gagal, penggunaan Hancurkan akan menghasilkan pengecualian pertama-tama akan memeriksa apakah Jika streaming tidak berhasil dibuat, maka akan dirilis hanya jika sudah dibuat, jadi lebih aman menggunakan Gratis.
Dalam program ini kami menggunakan kontrol NMUDP, yang memiliki beberapa properti penting. RemoteHost mewakili IP atau nama komputer dari komputer jarak jauh, dan LocalPort adalah port lokal, yang terutama memantau apakah ada data masuk. RemotePort adalah port jarak jauh, dan data dikirim melalui port ini saat mengirim data. Pemahaman ini sudah dapat memahami program kita.
Seluruh kodenya adalah sebagai berikut:
satuan Unit1;
antarmuka
kegunaan
Windows, Pesan, SysUtils, Kelas, Grafik, Kontrol, Formulir, Dialog, StdCtrls, ComCtrls, NMUDP;
jenis
TForm1 = kelas(TForm)
NMUDP1: TNMUDP;
SuntingIP: TEdit;
EditPort: TEdit;
EditTxt Saya: TEdit;
Penerimaan Memo: TMemo;
BtKirim: Tombol T;
BtClear: Tombol T;
Simpan Bt: Tombol T;
StatusBar1: TStatusBar;
SaveDialog1: TSaveDialog;
prosedur BtSendClick(Pengirim: TObject);
procedure NMUDP1DataReceived(Pengirim: TComponent; NumberBytes: Integer;
DariIP: String; Port: Integer);
prosedur NMUDP1InvalidHost(var ditangani: Boolean);
prosedur NMUDP1DataSend(Pengirim: TObject);
prosedur FormCreate(Pengirim: TObject);
prosedur BtClearClick(Pengirim: TObject);
prosedur BtSaveClick(Pengirim: TObject);
prosedur EditMyTxtKeyPress(Pengirim: TObject; var Key: Char);
pribadi
{Deklarasi pribadi}
publik
{Pernyataan publik}
akhir;
var
Formulir1: TForm1;
pelaksanaan
{$R *.DFM}
prosedur TForm1.BtSendClick(Pengirim: TObject);
var
Aliran Saya: TMemoryStream;
Kiriman SayaTxt: String;
Impor,icode:integer;
Mulai
Val(EditPort.Teks,Iport,icode);
jika icode<>0 maka
mulai
Application.MessageBox('Port harus berupa angka, silakan masukkan kembali!','Message',MB_ICONINFORMATION+MB_OK);
KELUAR;
akhir;
NMUDP1.RemoteHost := EditIP.Teks; {host jarak jauh}
NMUDP1.LocalPort:=Iport; {pelabuhan lokal}
NMUDP1.RemotePort := Impor; {port jarak jauh}
MySendTxt := EditMyTxt.Teks;
Aliran Saya := TMemoryStream.Buat; {Buat aliran}
mencoba
MyStream.Write(MySendTxt[1], Panjangnya(EditMyTxt.Text));{Tulis data}
NMUDP1.SendStream(MyStream); {Kirim aliran}
Akhirnya
Aliran Saya.Gratis; {rilis aliran}
akhir;
akhir;
procedure TForm1.NMUDP1DataReceived(Pengirim: TComponent;
NomorBytes: Integer; DariIP: String; Port: Integer);
var
Aliran Saya: TMemoryStream;
MyReciveTxt: String;
mulai
Aliran Saya := TMemoryStream.Buat; {Buat aliran}
mencoba
NMUDP1.ReadStream(MyStream);{Terima streaming}
SetLength(MyReciveTxt,NumberBytes);{NumberBytes adalah jumlah byte yang diterima}
MyStream.Read(MyReciveTxt[1],NumberBytes);{baca data}
MemoReceive.Lines.Add('Menerima informasi dari host '+FromIP+':'+MyReciveTxt);
Akhirnya
Aliran Saya.Gratis; {rilis aliran}
akhir;
akhir;
prosedur TForm1.NMUDP1InvalidHost(var ditangani: Boolean);
mulai
Application.MessageBox('Alamat IP pihak lain salah, silakan masukkan kembali!','Message',MB_ICONINFORMATION+MB_OK);
akhir;
prosedur TForm1.NMUDP1DataSend(Pengirim: TObject);
mulai
StatusBar1.SimpleText:='Pesan berhasil dikirim!';
akhir;
prosedur TForm1.FormCreate(Pengirim: TObject);
mulai
EditIP.Teks:='127.0.0.1';
EditPort.Teks:='8868';
BtSend.Caption:='Kirim';
BtClear.Caption:='Hapus riwayat obrolan';
BtSave.Caption:='Simpan riwayat obrolan';
MemoReceive.ScrollBars:=ssBoth;
MemoReceive.Clear;
EditMyTxt.Text:='Masukkan informasi di sini dan klik Kirim.';
StatusBar1.SimplePanel:=benar;
akhir;
prosedur TForm1.BtClearClick(Pengirim: TObject);
mulai
MemoReceive.Clear;
akhir;
prosedur TForm1.BtSaveClick(Pengirim: TObject);
mulai
jika SaveDialog1.Execute maka MemoReceive.Lines.SaveToFile(SaveDialog1.FileName);
akhir;
procedure TForm1.EditMyTxtKeyPress(Pengirim: TObject; var Key: Char);
mulai
jika Kunci=#13 maka BtSend.Klik;
akhir;
akhir.
Program diatas tentunya tertinggal jauh dari OICQ, karena OICQ menggunakan metode komunikasi Socket5. Saat online, pertama-tama ia mengambil informasi teman dan status online dari server. Saat waktu pengiriman habis, ia akan menyimpan informasi di server terlebih dahulu, menunggu pihak lain online lain kali, lalu mengirimkannya dan kemudian menghapusnya. cadangan server. Anda dapat meningkatkan program ini berdasarkan konsep yang Anda pelajari sebelumnya. Misalnya, menambahkan kontrol NMUDP untuk mengelola status online. Informasi yang dikirim terlebih dahulu diubah menjadi kode ASCII untuk operasi AND dan menambahkan informasi header setelahnya menerima informasi. Apakah header informasi benar atau tidak, informasi akan didekripsi dan ditampilkan hanya jika benar, sehingga meningkatkan keamanan dan kerahasiaan.
Selain itu, keuntungan besar lainnya dari protokol UDP adalah ia dapat menyiarkan, artinya siapa pun di segmen jaringan yang sama dapat menerima informasi tanpa menentukan alamat IP tertentu. Segmen jaringan umumnya dibagi menjadi tiga kategori: A, B, dan C.
1~126.XXX.XXX.XXX (Jaringan Kelas A): Alamat siarannya adalah XXX.255.255.255
128~191.XXX.XXX.XXX (jaringan Kelas B): Alamat siarannya adalah XXX.XXX.255.255
192~254.XXX.XXX.XXX (Jaringan Kategori C): Alamat siarannya adalah XXX.XXX.XXX.255
Misalnya, jika tiga komputer adalah 192.168.0.1, 192.168.0.10, dan 192.168.0.18, saat mengirim informasi, Anda hanya perlu menentukan alamat IP 192.168.0.255 untuk mencapai penyiaran. Di bawah ini adalah fungsi yang mengubah IP menjadi IP siaran. Gunakan untuk meningkatkan OICQ^-^ Anda sendiri.
Fungsi Trun_ip(S:string):string;
var s1,s2,s3,ss,sss,Kepala: string;
n,m: bilangan bulat;
mulai
sss:=S;
n:=pos('.',s);
s1:=salinan(s,1,n);
m:=panjang(s1);
hapus(s,1,m);
Kepala:=copy(s1,1,(panjang(s1)-1));
n:=pos('.',s);
s2:=salinan(s,1,n);
m:=panjang(s2);
hapus(s,1,m);
n:=pos('.',s);
s3:=salinan(s,1,n);
m:=panjang(s3);
hapus(s,1,m);
ss:=sss;
jika strtoint(Head) di [1..126] maka ss:=s1+'255.255.255'; //1~126.255.255.255 (jaringan Kelas A)
jika strtoint(Head) di [128..191] maka ss:=s1+s2+'255.255';//128~191.XXX.255.255 (jaringan Kelas B)
jika strtoint(Head) di [192..254] maka ss:=s1+s2+s3+'255'; //192~254.XXX.XXX.255 (Jaringan kategori)
Hasil:=ss;
akhir;
--------------------------------------------------- --------------------------
5. Aplikasi Praktis 4: Menggunakan aliran untuk mengirimkan gambar layar melalui jaringan
Anda seharusnya sudah melihat banyak program manajemen jaringan. Salah satu fungsi program tersebut adalah untuk memonitor layar komputer jarak jauh. Faktanya, hal ini juga dicapai dengan menggunakan operasi aliran. Di bawah ini kami berikan contohnya. Contoh ini dibagi menjadi dua program, satu adalah server dan yang lainnya adalah klien. Setelah program dikompilasi, program dapat digunakan langsung pada satu mesin, jaringan lokal atau Internet. Komentar yang sesuai telah diberikan dalam program ini. Kami akan membuat analisis rinci nanti.
Buat proyek baru dan seret kontrol ServerSocket ke jendela di panel Internet. Kontrol ini terutama digunakan untuk memantau klien dan menjalin koneksi serta komunikasi dengan klien. Setelah mengatur port pendengaran, panggil metode Open atau Active:=True untuk mulai bekerja. Catatan: Berbeda dengan NMUDP sebelumnya, setelah Socket mulai mendengarkan, portnya tidak dapat diubah, Anda harus terlebih dahulu memanggil Close atau mengatur Active ke False, jika tidak maka akan terjadi pengecualian. Selain itu jika port sudah terbuka maka port tersebut tidak dapat digunakan lagi. Oleh karena itu, Anda tidak dapat menjalankan program lagi sebelum program tersebut ditutup, jika tidak maka akan terjadi pengecualian, yaitu jendela kesalahan akan muncul. Dalam aplikasi praktis, kesalahan dapat dihindari dengan menentukan apakah program telah dijalankan dan keluar jika sudah berjalan.
Ketika data diteruskan dari klien, acara ServerSocket1ClientRead akan dipicu, dan kita dapat memproses data yang diterima di sini. Dalam program ini, program ini terutama menerima informasi karakter yang dikirim oleh klien dan melakukan operasi terkait sesuai dengan perjanjian sebelumnya.
Keseluruhan kode programnya adalah sebagai berikut:
unit Unit1;{program server}
antarmuka
kegunaan
Windows, Pesan, SysUtils, Kelas, Grafik, Kontrol, Formulir, Dialog, JPEG, ExtCtrls, ScktComp;
jenis
TForm1 = kelas(TForm)
ServerSocket1: TServerSocket;
procedure ServerSocket1ClientRead(Pengirim: TObject;Socket: TCustomWinSocket);
prosedur FormCreate(Pengirim: TObject);
procedure FormClose(Pengirim: TObject; var Action: TCloseAction);
pribadi
prosedur Cjt_GetScreen(var Mybmp: TBitmap; DrawCur: Boolean);
{Fungsi tangkapan layar yang disesuaikan, DrawCur menunjukkan apakah akan mengambil gambar mouse}
{Deklarasi pribadi}
publik
{Pernyataan publik}
akhir;
var
Formulir1: TForm1;
Aliran Saya: TMemorystream;{objek aliran memori}
pelaksanaan
{$R *.DFM}
prosedur TForm1.Cjt_GetScreen(var Mybmp: TBitmap; DrawCur: Boolean);
var
Kursorx, Cursory: bilangan bulat;
dc:hdc;
Mycan: Kanvas;
R: Benar;
DrawPos: TPoint;
Kursor Saya: TIcon;
pegang: hwnd;
Threadld: kata sandi;
mp: titik;
pIconInfo: TIconInfo;
mulai
Mybmp := Tbitmap.Buat; {Buat BMPMAP}
Mycan := TCanvas.Buat; {tangkapan layar}
dc := GetWindowDC(0);
mencoba
Mycan.Handle := dc;
R := Persegi(0, 0, layar.Lebar, layar.Tinggi);
Mybmp.Lebar := R.Kanan;
Mybmp.Tinggi := R.Bawah;
Mybmp.Canvas.CopyRect(R, Mycan, R);
Akhirnya
rilisDC(0, DC);
akhir;
Mycan.Handle := 0;
Mycan.Gratis;
jika DrawCur maka {Gambarlah gambar mouse}
mulai
DapatkanCursorPos(DrawPos);
Kursor Saya := TIcon.Buat;
getcursorpos(mp);
hld := WindowFromPoint(mp);
Threadld := GetWindowThreadProcessId(hld, nihil);
LampirkanThreadInput(GetCurrentThreadId, Threadld, Benar);
Kursor Saya.Handle := Getcursor();
LampirkanThreadInput(GetCurrentThreadId, threadld, False);
GetIconInfo(kursor saya.Handle, pIconInfo);
kursorx := DrawPos.x - bulat(pIconInfo.xHotspot);
sepintas := DrawPos.y - bulat(pIconInfo.yHotspot);
Mybmp.Canvas.Draw(kursorx, sepintas, MyCursor); {Gambar di mouse}
DeleteObject(pIconInfo.hbmColor);{GetIconInfo membuat dua objek bitmap saat digunakan.
DeleteObject(pIconInfo.hbmMask); {Jika tidak, setelah memanggilnya, itu akan membuat bitmap, dan beberapa panggilan akan menghasilkan banyak bitmap hingga sumber daya habis}
Mycursor.ReleaseHandle; {Lepaskan memori array}
MyCursor.Free; {lepaskan penunjuk tetikus}
akhir;
akhir;
prosedur TForm1.FormCreate(Pengirim: TObject);
mulai
ServerSocket1.Port := 3000;
ServerSocket1.Open; {Socket mulai mendengarkan}
akhir;
procedure TForm1.FormClose(Pengirim: TObject; var Action: TCloseAction);
mulai
jika ServerSocket1.Active maka ServerSocket1.Close;
akhir;
prosedur TForm1.ServerSocket1ClientRead(Pengirim: TObject;
Soket: TCustomWinSocket);
var
S, S1: tali;
Bmp Saya: TBitmap;
JPG saya: TJpegimage;
mulai
S := Socket.ReceiveText;
if S = 'cap' maka {Klien mengeluarkan perintah tangkapan layar}
mulai
mencoba
MyStream := TMemorystream.Create;{Buat aliran memori}
MyBmp := TBitmap.Buat;
Myjpg := TJpegimage.Buat;
Cjt_GetScreen(MyBmp, True); {True berarti mengambil gambar mouse}
Myjpg.Assign(MyBmp); {Konversi gambar BMP ke format JPG untuk kemudahan transmisi di Internet}
Myjpg.CompressionQuality := 10; {Pengaturan persentase kompresi file JPG, semakin besar angkanya, semakin jelas gambarnya, tetapi semakin besar datanya}
Myjpg.SaveToStream(MyStream); {Tulis gambar JPG untuk streaming}
Myjpg.gratis;
MyStream.Position := 0;{Catatan: Kalimat ini harus ditambahkan}
s1 := inttostr(MyStream.size);{ukuran aliran}
Socket.sendtext(s1); {kirim ukuran aliran}
Akhirnya
MyBmp.gratis;
akhir;
akhir;
if s = 'siap' maka {Klien siap menerima gambar}
mulai
Aliran Saya.Posisi := 0;
Socket.SendStream(MyStream); {Kirim aliran}
akhir;
akhir;
akhir.
Di atas adalah servernya, mari kita tulis program kliennya di bawah ini. Buat proyek baru dan tambahkan kontrol Socket ClientSocket, kontrol tampilan gambar Gambar, Panel, Edit, dua Tombol dan kontrol bilah status StatusBar1. Catatan: Tempatkan Edit1 dan dua Tombol di atas Panel1. Atribut ClientSocket mirip dengan ServerSocket, tetapi ada tambahan atribut Address yang menunjukkan alamat IP server yang akan dihubungkan. Setelah mengisi alamat IP, klik "Hubungkan" untuk menjalin koneksi dengan program server. Jika berhasil, komunikasi dapat dimulai. Mengklik "Tangkapan Layar" akan mengirim karakter ke server. Karena program menggunakan unit gambar JPEG, maka Jpeg harus ditambahkan ke Kegunaan.
Seluruh kodenya adalah sebagai berikut:
unit Unit2{klien};
antarmuka
kegunaan
Windows, Pesan, SysUtils, Kelas, Grafik, Kontrol, Formulir, Dialog, StdCtrls, ScktComp, ExtCtrls, Jpeg, ComCtrls;
jenis
TForm1 = kelas(TForm)
ClientSocket1: TClientSocket;
Gambar1: Gambar;
StatusBar1: TStatusBar;
Panel1: TPanel;
Sunting1: TEdit;
Tombol1: Tombol T;
Tombol2: Tombol T;
prosedur Button1Click(Pengirim: TObject);
prosedur ClientSocket1Connect(Pengirim: TObject;
Soket: TCustomWinSocket);
prosedur Button2Click(Pengirim: TObject);
prosedur ClientSocket1Error(Pengirim: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var Kode Kesalahan: Integer);
prosedur ClientSocket1Read(Pengirim: TObject; Socket: TCustomWinSocket);
prosedur FormCreate(Pengirim: TObject);
procedure FormClose(Pengirim: TObject; var Action: TCloseAction);
prosedur ClientSocket1Disconnect(Pengirim: TObject;
Soket: TCustomWinSocket);
pribadi
{Deklarasi pribadi}
publik
{Pernyataan publik}
akhir;
var
Formulir1: TForm1;
Ukuran Saya: Longint;
Aliran Saya: TMemorystream;{objek aliran memori}
pelaksanaan
{$R *.DFM}
prosedur TForm1.FormCreate(Pengirim: TObject);
mulai
{-------- Berikut ini untuk mengatur properti tampilan kontrol jendela------------- }
{Catatan: Tempatkan Button1, Button2 dan Edit1 di atas Panel1}
Sunting1.Teks := '127.0.0.1';
Button1.Caption := 'Hubungkan ke host';
Button2.Caption := 'Tangkapan layar';
Tombol2.Diaktifkan := false;
Panel1.Sejajarkan := alTop;
Gambar1.Sejajarkan := alClient;
Gambar1.Regangan := Benar;
StatusBar1.Align:=alBottom;
StatusBar1.SimplePanel := Benar;
{------------------------------------------------- ---------}
MyStream := TMemorystream.Create; {Buat objek aliran memori}
Ukuran Saya := 0; {inisialisasi}
akhir;
prosedur TForm1.Button1Click(Pengirim: TObject);
mulai
jika bukan ClientSocket1.Active maka
mulai
ClientSocket1.Address := Edit1.Teks; {alamat IP jarak jauh}
ClientSocket1.Port := 3000; {Port soket}
ClientSocket1.Buka; {Buat koneksi}
akhir;
akhir;
prosedur TForm1.Button2Click(Pengirim: TObject);
mulai
Clientsocket1.Socket.SendText('cap'); {Kirim perintah untuk memberi tahu server agar mengambil gambar layar}
Button2.Enabled := Salah;
akhir;
prosedur TForm1.ClientSocket1Connect(Pengirim: TObject;
Soket: TCustomWinSocket);
mulai
StatusBar1.SimpleText := 'Dengan host' + ClientSocket1.Address + 'Koneksi berhasil dibuat!';
Button2.Enabled := Benar;
akhir;
prosedur TForm1.ClientSocket1Error(Pengirim: TObject;
Soket: TCustomWinSocket; ErrorEvent: TErrorEvent;
varErrorCode: Bilangan Bulat);
mulai
Kode Kesalahan := 0; {Jangan memunculkan jendela kesalahan}
StatusBar1.SimpleText := 'Tidak dapat terhubung ke host' + ClientSocket1.Address + 'Koneksi terjalin!';
akhir;
prosedur TForm1.ClientSocket1Disconnect(Pengirim: TObject;
Soket: TCustomWinSocket);
mulai
StatusBar1.SimpleText := 'Dengan host' + ClientSocket1.Address + 'Putuskan sambungan!';
Button2.Enabled := Salah;
akhir;
procedure TForm1.ClientSocket1Read(Pengirim: TObject;
Soket: TCustomWinSocket);
var
MyBuffer: array[0..10000] byte; {Atur buffer penerimaan}
PanjangRecevice Saya: bilangan bulat;
S: tali;
Bmp Saya: TBitmap;
MyJpg: TJpegimage;
mulai
StatusBar1.SimpleText := 'Menerima data...';
jika MySize = 0 maka {MySize adalah jumlah byte yang dikirim oleh server. Jika 0 berarti penerimaan gambar belum dimulai}
mulai
S := Socket.ReceiveText;
MySize := Strtoint(S); {Tetapkan jumlah byte yang akan diterima}
Clientsocket1.Socket.SendText('ready'); {Kirim perintah untuk memberi tahu server agar mulai mengirim gambar}
akhir
kalau tidak
mulai {Berikut ini adalah bagian penerimaan data gambar}
MyReceviceLength := socket.ReceiveLength; {baca panjang paket}
StatusBar1.SimpleText := 'Menerima data, ukuran datanya adalah:' + inttostr(MySize);
Socket.ReceiveBuf(MyBuffer, MyReceviceLength); {Terima paket data dan baca ke dalam buffer}
MyStream.Write(MyBuffer, MyReceviceLength); {Menulis data ke dalam aliran}
if MyStream.Size >= MySize maka {Jika panjang streaming lebih besar dari jumlah byte yang akan diterima, penerimaan selesai}
mulai
Aliran Saya.Posisi := 0;
Bmp Saya := tbitmap.Buat;
MyJpg := tjpegimage.Buat;
mencoba
MyJpg.LoadFromStream(MyStream); {Baca data dalam aliran ke dalam objek gambar JPG}
MyBmp.Assign(MyJpg); {Konversi JPG ke BMP}
StatusBar1.SimpleText := 'Menampilkan gambar';
Image1.Picture.Bitmap.Assign(MyBmp); {Ditugaskan ke elemen image1}
akhirnya {Berikut ini adalah pekerjaan pembersihan}
MyBmp.gratis;
MyJpg.gratis;
Tombol2.Diaktifkan := benar;
{Socket.SendText('cap');Tambahkan kalimat ini untuk menangkap layar secara terus menerus}
Aliran Saya.Bersihkan;
Ukuran Saya := 0;
akhir;
akhir;
akhir;
akhir;
procedure TForm1.FormClose(Pengirim: TObject; var Action: TCloseAction);
mulai
MyStream.Free; {Lepaskan objek aliran memori}
jika ClientSocket1.Active maka ClientSocket1.Close; {Tutup koneksi Socket}
akhir;
akhir.
Prinsip program: Jalankan server untuk mulai mendengarkan, lalu jalankan klien, masukkan alamat IP server untuk membuat sambungan, lalu kirim karakter untuk memberi tahu server agar menangkap layar. Server memanggil fungsi khusus Cjt_GetScreen untuk menangkap layar dan menyimpannya sebagai BMP, mengonversi BMP ke JPG, menulis JPG ke dalam aliran memori, dan kemudian mengirimkan aliran tersebut ke klien. Setelah menerima aliran, klien melakukan operasi sebaliknya, mengubah aliran ke JPG dan kemudian ke BMP dan kemudian menampilkannya.
Catatan: Karena keterbatasan Socket, data yang terlalu besar tidak dapat dikirim sekaligus, tetapi hanya dapat dikirim beberapa kali. Oleh karena itu, dalam program, setelah mengubah tangkapan layar menjadi aliran, server terlebih dahulu mengirimkan ukuran aliran untuk memberi tahu klien seberapa besar aliran tersebut ya, itu akan dikonversi dan ditampilkan.
Program ini dan OICQ buatan sendiri sebelumnya sama-sama menggunakan objek aliran memori TMemoryStream. Faktanya, objek aliran ini adalah yang paling umum digunakan dalam pemrograman. Ini dapat meningkatkan kemampuan membaca dan menulis I/O, dan jika Anda ingin mengoperasikan beberapa jenis aliran yang berbeda secara bersamaan dan bertukar data satu sama lain, gunakan itu sebagai seorang "perantara" Itu yang terbaik. Misalnya, jika Anda mengompresi atau mendekompresi aliran, pertama-tama Anda membuat objek TMemoryStream, lalu menyalin data lain ke dalamnya, lalu melakukan operasi terkait. Karena bekerja langsung di memori, efisiensinya sangat tinggi. Terkadang Anda bahkan tidak menyadari adanya penundaan.
Area yang perlu ditingkatkan dalam program ini: Tentu saja, Anda dapat menambahkan unit kompresi untuk dikompres sebelum dikirim dan kemudian dikirim. Catatan: Disini juga ada triknya yaitu dengan mengompres BMP secara langsung, bukan mengubahnya menjadi JPG lalu mengompresnya. Eksperimen menunjukkan bahwa ukuran gambar pada program di atas adalah sekitar 40-50KB. Jika diproses menggunakan algoritma kompresi LAH, hanya akan menjadi 8-12KB, yang membuat transmisi lebih cepat. Jika Anda ingin lebih cepat, Anda dapat menggunakan metode ini: pertama-tama ambil gambar pertama dan kirimkan, lalu mulai dari gambar kedua dan hanya kirim gambar di area yang berbeda dari yang sebelumnya. Ada program asing bernama Remote Administrator yang menggunakan metode ini. Data yang mereka uji adalah sebagai berikut: 100-500 frame per detik di jaringan lokal, dan 5-10 frame per detik di Internet saat kecepatan jaringan sangat rendah. Penyimpangan-penyimpangan ini hanya ingin menggambarkan satu kebenaran: ketika memikirkan suatu masalah, terutama ketika menulis sebuah program, terutama program yang terlihat sangat rumit, jangan terlalu terjebak di dalamnya . Program sudah mati, bakat masih hidup. Tentu saja, ini hanya bisa mengandalkan akumulasi pengalaman. Namun membentuk kebiasaan baik sejak awal akan membuahkan hasil sepanjang hidup Anda!