ورود

View Full Version : ارسال و دریافت فایل در شبکه Send File Socket



saeidsg
جمعه 26 اسفند 1390, 01:15 صبح
سورس برنامه ها هست ارسال و دریافت به خوبی کارمی کنه ولی اگر هم زمان اگر چند فایل ارسال بشود نمی توانم کنترل کنم خواهش می کنم کمک کنید با تشکر


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Edit1: TEdit;
Edit2: TEdit;
GroupBox1: TGroupBox;
Label1: TLabel;
Label2: TLabel;
ClientSocket1: TClientSocket;
ClientSocket2: TClientSocket;
Edit3: TEdit;
Label3: TLabel;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket2Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
Streamsize: TFileStream;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// Written by Me ColdFuzion
// Program Purpose : To Sendfiles to the recieving file program
// All i ask is whoever uses my code gives me a little credit my e-mail is ColdFuzion@hushmail.com
// Reason for using 2 sockets is because its meant to be more like a messenger client where one socket is used for communication and so on.. while the other is soley used for sending files
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Address := Edit3.Text;
ClientSocket1.Open; // Open rather than active so it can bypass firewalls
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Connected to ' +Socket.RemoteHost); // Shows the address of the server you connect to
end;
procedure TForm1.ClientSocket2Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Sending File ' +Edit1.Text +' .........')
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if ClientSocket1.Active = True then
begin
OpenDialog1.Filter := 'All Files (*.*)'; // you can add more choices by adding | and followed by description and (*.extension)
OpenDialog1.FilterIndex := 1; // Here you follow which index number from above you want
if OpenDialog1.Execute then
begin
Edit1.Text := ExtractFileName(OpenDialog1.FileName); // To send as filename after
ClientSocket1.Socket.SendText('FILE!'+Edit1.Text);
sleep(800); // Need to sleep so the other end has time to process the commands
Streamsize := TFileStream.Create(OpenDialog1.FileName, fmopenread); // Stream created just to Calculate size
Edit2.Text := inttostr(Streamsize.Size);
Sleep(800);
ClientSocket1.Socket.SendText('SIZE!'+Edit2.Text); // Sends filesize through primary socket
Streamsize.Position := 0;
Streamsize.Free;
sleep(800);
ClientSocket2.Address := Edit3.Text;
ClientSocket2.Open; // ready to send file on second socket
if ClientSocket2.Socket.SendStream(TFileStream.Create (OpenDialog1.FileName, fmopenRead)) then memo1.Lines.Add('File Sent');
// above creates a stream and sends as a stream its in a if line because this is the only way it will automatically check the byte order and send the whole stream
end;
end
else
MessageDlg('Error: You are not connected', mtError, [MbOK],0); // Error Check above code won't work until the socket is connected
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Text := '';
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var IncommingText, StrippedData, CommandName: string;
begin
IncommingText := socket.ReceiveText; // Put all incoming data into this string
StrippedData := copy(IncommingText,6,length(IncommingText) ); // letters 6 to end is the actual data being sent
CommandName := copy(IncommingText,0,5); // letters 0 to 5 is the fixed letter space for the command name
if CommandName = 'DONE!' then // Expected command Done! note : This is case sensitive so match has to be the same case
begin
Memo1.Lines.Add('File ' +Edit1.Text +' ' +Edit2.Text +' was Recieved Successfully');
ClientSocket2.Active := False; // Turns off the file sending socket as file confirmation has been sent from the other end
Edit1.Text := '';
Edit2.Text :='';
end;
end;
end.




================================================== ===============


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp, ComCtrls, idglobal, ExtCtrls, ShellAPI;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Label1: TLabel;
ServerSocket1: TServerSocket;
ServerSocket2: TServerSocket;
GroupBox1: TGroupBox;
Edit1: TEdit;
Edit2: TEdit;
Label2: TLabel;
Label3: TLabel;
ProgressBar1: TProgressBar;
Timer1: TTimer;
StatusBar1: TStatusBar;
procedure Button1Click(Sender: TObject);
procedure ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket2Accept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket2ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
IncommingStream: TFileStream;
TimeTaken: integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
iCount : Integer;
implementation
{$R *.dfm}
// Written by me ColdFuzion
// All i ask is i be given some credit for coding this my e-mail is ColdFuzion@hushmail.com
// Program Usage: To recieve Files sent by the client
procedure TForm1.Button1Click(Sender: TObject);
begin
iCount := 0;
ServerSocket1.Open;
Memo1.Lines.Add('Server Listening on '+inttostr(ServerSocket1.Port) );
end;
procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Client connected From '+Socket.RemoteHost)
// Adds the clients host as it connects
end;
procedure TForm1.ServerSocket2Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
Memo1.Lines.Add('Incoming File Transfer');
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
IncommingText, StrippedData, CommandName: string;
begin
IncommingText := socket.ReceiveText;
StrippedData := copy(IncommingText,6,length(IncommingText) );
CommandName := copy(IncommingText,0,5);

if CommandName = 'FILE!' then begin
IncommingStream := TFileStream.Create(StrippedData, fmCREATE or fmOPENWRITE and fmsharedenywrite); // Once File name is recieved the stream to recieve
Edit1.Text := StrippedData; // The file is created
ServerSocket2.Open;
end else
if CommandName = 'SIZE!' then begin
Edit2.Text := StrippedData;
ProgressBar1.Max := StrToInt(StrippedData);
ProgressBar1.Min := 0;
Memo1.lines.Add('Recieving File '+Edit1.Text +' of size '+Edit2.Text);
end;
if iCount = 5 then iCount := 0;
Inc(iCount);
end;
procedure TForm1.ServerSocket2ClientRead(Sender: TObject;
// This is the secondary socket it is the most important part of the program
Socket: TCustomWinSocket);
// It processes the incomming file stream
var Buffer: array [0..9999] of Char;
IncommingLen, RecievedLen: integer;
Filepath: string;
begin
Buffer := '';
Timer1.Enabled := True;
IncommingLen := socket.ReceiveLength;
// If the size of any incomming data is the size of 0 then the process begins
Filepath := ExtractFilePath(Edit1.Text)+Edit1.Text;
// Sets a String Filepath for the actual directory with the filename so that the shellexecute can run this after
while IncommingLen > 0 do
// Must make sure the process ends
begin
RecievedLen := socket.ReceiveBuf(Buffer, Sizeof(Buffer));
// Changes the size of RecievedLen by the amount of incoming data recieved
if RecievedLen <= 0 then
// Small part of the code where once the buffer reaches 0 the code will exit
Break
else
IncommingStream.Write(Buffer, RecievedLen);
// Writes the Incoming data into a new stream by the filename and size which is recieved
ProgressBar1.StepBy(RecievedLen);
// through the primary socket Also this line increases the progess indicator bar
if IncommingStream.Size >= strtoint(Edit2.Text) then
// Onces the stream size begins to reach the size which was sent before sending the file then this
begin
// procedure will start
IncommingStream.Free;
// Free's the stream
memo1.Lines.Add('File '+Edit1.Text +' Recieved Successfuly');
memo1.Lines.Add('Time Taken to Recieve File ' +IntToStr(TimeTaken)+' seconds');
ServerSocket1.Socket.Connections[0].SendText('DONE!');
Edit1.Text := '';
// From here it starts setting the variables back
Edit2.Text := '';
ProgressBar1.Position := 0;
Timer1.Enabled := False;
TimeTaken := 0;
{ if Messagedlg('Would you Like to open the recieved file?', mtConfirmation, [MbYes,MbNo],0) = MrYes then // Simply asks the user if he wants to open the file if yes will execute if no break
begin
ShellExecute(Form1.Handle, 'open', pchar(Filepath),nil, nil, SW_NORMAL); // A shellapi was added to uses to beable to execute this line
end;}
Break; // This line basically executes any file using the extension from the windows ini files.
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Text := '';
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
inc(TimeTaken,1);
// Counts number of seconds starts once the filestream begins
end;
end.

بهروز عباسی
جمعه 26 اسفند 1390, 02:24 صبح
درود به شما دوست عزیز:لبخند:
اول اینکه لطفاًجهت خوانای کد اونو داخل تگ مخصوص کد بذارید.:گریه:
دوم (فکرکنم:متفکر:) برای اینکه بصورت همزمان بتونی این کارو بکنی باید از Threadها استفاده کنی چون این کد بصورت ایستا فقط برای ارسال و دریافت یک فایل طراحی شده.
یاعلی.

vcldeveloper
جمعه 26 اسفند 1390, 12:44 عصر
دوم (فکرکنم:متفکر:) برای اینکه بصورت همزمان بتونی این کارو بکنی باید از Threadها استفاده کنی چون این کد بصورت ایستا فقط برای ارسال و دریافت یک فایل طراحی شده.
ClientSocket به صورت Asynchronous عمل میکنه، و خودش برای ارسال و دریافت داده Thread ایجاد میکنه، پس ارتباطی به Thread نداره.


ولی اگر هم زمان اگر چند فایل ارسال بشود نمی توانم کنترل کنم
خب وقتی چند فایل ارسال می کنید، همه آنها دارند از یک سوکت استفاده می کنند، پس داده های همه آنها از طریق همون یک سوکت به صورت استریم ارسال میشه. در سمت گیرنده هم داره روی یک پورت خاص Listen میشه، و هر چی از اون پورت به سیستم برسه، دریافت میشه. نتیجه اش این میشه که گیرنده مجموعه ایی از بسته ها رو بدون ترتیب مشخصی دریافت میکنه، و نمیدونه که کدوم بسته مربوط به کدوم فایل هست. شما باید یا فایل هایتان را به صورت پشت سر هم ارسال کنید، یعنی فایل ها در یک صف قرار بگیرند و با اتمام ارسال هر فایل، فایل بعدی ارسال شود؛ یا از چند سوکت برای ارسال و دریافت داده استفاده کنید، یعنی هر فایل بر روی یک سوکت مجزا ارسال شود؛ یا اینکه از همون یک سوکت استفاده کنید، اما هر بسته ایی که ارسال میشه، Header ایی داشته باشه که مشخص کنه که مربوط به چه فایلی هست، تا در سمت گیرنده، اون بسته به همون فایل اضافه بشه. در حالت آخر شما باید خودتون یک پروتکل انتقال فایل بر روی TCP یا UDP طراحی کنید، و فایل ها را خودتان به Chunk هایی تقسیم کنید، و هر Chunk برای خودش Header ایی داشته باشه که مشخص کنه اون Chunk مربوط به کدوم فایل هست، و باید در کدوم قسمت فایل ذخیره بشه (مثلا Chunk شماره 180 از فایل شماره 1).

بهروز عباسی
جمعه 26 اسفند 1390, 15:18 عصر
درود جناب کشاورز

یا از چند سوکت برای ارسال و دریافت داده استفاده کنید، یعنی هر فایل بر روی یک سوکت مجزا ارسال شود؛ یا اینکه از همون یک سوکت استفاده کنید، اما هر بسته ایی که ارسال میشه، Header ایی داشته باشه که مشخص کنه که مربوط به چه فایلی هست،

کدم روش سریعترانجام میشه ؟

Felony
جمعه 26 اسفند 1390, 16:37 عصر
کدم روش سریعترانجام میشه ؟
طبیعتا ارسال فایل ها به صورت پارالل توسط سوکت های مجزا .

vcldeveloper
جمعه 26 اسفند 1390, 16:47 عصر
کدم روش سریعترانجام میشه ؟
منظور سریع تر شدن کارایی برنامه هست یا سریع تر آماده شدن کد توسط برنامه نویس؟

روش اول ساده تر هست، کارایی اش هم میتونه بهتر باشه، با توجه به اینکه لازم نیست خودتون اطلاعات اضافی ارسال کنید، یا درگیر قسمت کردن فایل بشید، اما از نظر مفید بودن محدودیت داره. اگر تعداد فایل هایی که همزمان ارسال می کنید کم باشه (مثلا 2 یا 4 فایل)، اون وقت شاید استفاده از چند سوکت بهتر باشه، اما اگر تعداد فایل های همزمان زیاد باشه، اصلا کار جالبی نیست، مثلا اگر بخواید 20 فایل همزمان ارسال کنید، در سمت گیرنده هم باید 20 پورت باز باشه، و برای هر پورت یک Thread در حال Listen باشه! استفاده از یک پروتکل خاص که در اون مشخص باشه هر بسته برای چه فایلی هست، منطقی تر هست، و روشی هست که خیلی از نرم افزارها استفاده می کنند.

بهروز عباسی
جمعه 26 اسفند 1390, 17:11 عصر
منظور سریع تر شدن کارایی برنامه هست یا سریع تر آماده شدن کد توسط برنامه نویس؟
منظورم سریع تر شدن کارایی برنامه بود
که فکر کنم در کل روش دوم اگه سریعتر نباشه مطمئن تره.:متفکر:

Felony
جمعه 26 اسفند 1390, 18:03 عصر
من بودم اگر از نظر برنامه نویسی مشکلی نداشته باشی همون روش ارسال پارالل فایل ها رو انتخاب میکردم با این تفاوت که تعداد پورت های در حال Listen رو محدود میکردم ، مثلا میگفتم بسته به تعداد فایل ها اگر تعداد فایل ها زیر 4 تا بود به تعداد فایل ها پورت به برنامه اختصاص داده بشه ( مثلا اگر 3 تا فایل بود ، 3 تا پورت ) و اگر از 4 تا بیشتر شد کلا 4 تا پورت به برنامه اختصاص داده بشه و فایل ها تو 4 تا صف تقسیم بشن و به صورت پارالل از طریق این 4 تا پورت ارسال بشن ؛ البته مدیریت همچین پروسه ای کار مشکلی هست ولی در کل سناریوی خوبی هست .

saeidsg
یک شنبه 28 اسفند 1390, 13:12 عصر
لطفا آقای کشاورز الگوریتم شما منطقی تر است که هندل هرفال ارسال شود لطفا اگر اماکن دارد شما
سورس شما متوانید کامل نمایید باتشکر

mohinsoft
شنبه 18 شهریور 1391, 08:45 صبح
سلام مطلب زیر مفید باید باشه:
When working with sockets in Windows, multiple approaches are possible. Reading data
from a socket or writing to it can happen asynchronously, so that it does not block the execution
of other code in your network application. This is called a nonblocking connection. Nonblocking
connections read and write asynchronously: the Windows socket support basically
sends a message when data is available. Using the ClientSocket and ServerSocket components,
for example, the system fires the OnRead or OnWrite events of the client, and the
OnClientRead or OnClientWrite events of servers inform your socket when the other end of
the connection tries to read or write some data.
As an alternative to the asynchronous approach, you can also use blocking connections, where
your application waits for the reading or writing to be completed before executing the next
line of code. In this case, you have to write the code in sequence on both sides, because otherwise
the events won’t be triggered. When using a blocking connection, you must use a thread
on the server, and you’ll generally use a thread also on the client.
The Indy components use an in-between approach. They use blocking connections exclusively,
and you can either place their code in a thread or use a special helper component
(IdAntiFreeze). Using blocking connections for implementing a protocol has the advantage
of simplifying the program logic, because you don’t have to use the state-machine approach
of nonblocking connections, as exemplified later.
Finally, when writing threaded code with the ServerSocket components working on a
blocking connection, you can use the TWinSocketStream class to do the actual reading and
writing operations. You can use the WaitForData method of the TWinSocketStream class to
wait until the socket on the other end is ready to write. You can also create the socket stream
class and specify a timeout value, so that if the connection is lost, it won’t hang forever.