Delphi é poderoso. Escrever software com Delphi pode reduzir bastante o ciclo de desenvolvimento de software. A ideia básica da transferência de arquivos ponto a ponto é que um software servidor e um software cliente usem a mesma porta. Depois de conectado, o cliente envia uma solicitação ao servidor, incluindo o nome do arquivo, tamanho, etc. o arquivo a ser transferido Se o servidor aceitar e iniciar a transferência de arquivos. Claro, existem dois modos de transferência de arquivos, código ASCII e Bin, mas geralmente Bin é suficiente. Com base na discussão acima, originalmente era possível usar os controles NMStrm e NMStrmServ do Delphi4. No entanto, testei-o e descobri que o controle NNMStrm pode ser usado para arquivos menores e é muito conveniente se o arquivo for grande (1M). ), ocorrerá um erro. Então, a seguir, usamos TServerSocket e TClientSocket no Delphi para escrever este programa. Devido à limitação do tamanho do pacote Ethernet e ao mecanismo de processamento do DelphiSocket (no Delphi, quando você usa um Socket para enviar um Stream maior, o receptor irá acionar OnRead várias vezes. . evento, o Delphi apenas garante a integridade de cada dado em vários eventos OnRead, e não coleta os dados em si e os devolve ao usuário, então não pense que você pode enviar o arquivo para ser transferido uma vez em um Socket e Recv uma vez em outro, você mesmo deve coletar os dados ou definir o protocolo), então adotamos o método de protocolo personalizado. A maneira canônica de definir um protocolo é usar Record End. como:
TMyFilePRotocol=Registro
sSendType=(ST_QUERY,ST_REFUSE,ST_DATA,ST_ABORT,...);
iComprimento: inteiro;
bufEnviar:Buffer;
Fim;
Eu tentei esse método, mas ele falhou, e sempre pensei que meu método estava correto, mas o programa sempre falhava ao compilar. Acho que havia algo errado com o Delphi :) Então usei outro método no programa de exemplo a seguir. Existem duas propriedades, ReceiveText e ReceiveBuf, na classe Socket. Em um evento OnRead, essas duas propriedades só podem ser usadas uma vez, portanto podemos usar uma variável global para salvar se devemos ler Text ou Buf, ou seja, ler. Envie uma mensagem de texto uma vez e leia novamente Buf, isso simula TMyFileProtocol.
Inicie o programa:
Escreva o mais simples, usado principalmente para explicar o método.
Definir protocolo:
Const.
MP_QUERY='1';
MP_REFUSE ='2';
MP_ACEITAR ='3';
MP_NEXTWILLBEDATA='4';
MP_DADOS ='5';
MP_ABORT='6';
MP_OVER='7';
MP_CHAT='8';
Introdução do acordo:
Primeiramente o Cliente envia MP_QUERY, e após recebê-lo o Servidor envia MP_ACCEPT ou MP_FEFUESE;
O Cliente envia MP_FILEPROPERTY após receber MP_ACCEPT, e o Servidor envia MP_NEXTWILLBEDATA após recebê-lo;
O Cliente envia MP_NEXTWILLBEDATA após recebê-lo, e o Servidor envia MP_DATA após recebê-lo;
Cliente recebe MP_DATA e envia dados, Servidor recebe dados e envia MP_NEXTWILLBEDATA;
Loop até que o cliente envie MP_OVER;
MP_CHAT+String podem ser enviados um ao outro no meio;
Programa de servidor:
Coloque os seguintes controles:SaveDialog1,btnStartServer,
ss,(TServerSocket)
btnStartServer.OnClick(Sender:TObject);
começar
ss.Porta:=2000;
ss.Abrir;
fim;
ss.OnClientRead(Remetente: TObject;Socket: TCustomWinSocket);
var
temperatura:string;
bufRecv:Ponteiro;
iRecvLength:inteiro;
começar
se bReadText então
começar
sTemp:=Socket.ReceiveText;
caso Temp[1] de
MP_QUERY:início
//Rejeite aqui
SaveDialog1.FileName:=Copiar(sTemp,2,Comprimento(STemp));
se SaveDialog1.Execute então
começar
Socket.SendText(MP_ACCEPT);
fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
fim
senão Socket.SendText(MP_REFUSE+'die');
fim;
MP_FILEPROPERTY:início
//Para enviar StrToInt(Copy(sTemp,2,Length(sTemp))) vezes
//Exibição do progresso do tempo. . .
Socket.SendText(MP_NEXTWILLBEDATA);
fim;
MP_NEXTWILLBEDATA:início
Socket.SendText(MP_DATA);
bReadText:=falso;
fim;
MP_END:início
fsRecv.Free
bReadText:=true;
fim;
MP_ABORT:início
fsRecv.Free;
bReadText:=true;
fim;
MP_CHAT:início
//Mensagem de bate-papo
fim;
fim;{do caso}
fim
senão começar
tentar
GetMem(bufRecv,2000);//2000 deve >iBYTESEND
Socket.ReceiveBuf(bufRecv^,iRecvLength);
fsRecv.WriteBuffer(bufRecv^,iRecvLength);
finalmente
FreeMem(bufRecv,2000);
fim;{de tentativa}
bReadText:=true;
Socket.SendText(MP_NEXTWILLBEDATA);
fim;
fim;
Programa cliente:
Coloque os seguintes controles: edtipAddress, OpenDialog1, btnConnect, btnSendFile,
cs.(TClientSocket)
btnConnect.OnClick(Sender:TObject);
começar
cs.Address:=edtIPAddress.Text;
cs.Port:=2000;
cs.Conectar;
fim;
btnSendFile.OnClick(Sender:TObject);
começar
se OpenDialog1.Execute então
Começar
cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName); //Tamanho do arquivo???
fim;
fim;
cs.OnRead(Remetente: TObject;Socket: TCustomWinSocket);
var
temperatura:string;
bufSend:ponteiro;
começar
sRecv:=Socket.ReceiveText;
Caso sRecv[1] de
MP_REFUSE:ShowMessage('Fraco,seja recusado!');
MP_ACCEPT:início
fsSend:=TFileStream.Create(OpenDialog1.FileName,fmOpen);
//iBYTEPERSEND é uma constante, o tamanho do pacote enviado a cada vez.
Socket.SendText(MP_FILEPROPERTY+Trunc(fsSend.Size/iBYTEPERSEND)+1);
fim;
MP_NEXTWILLBEDATA:início
Socket.SendText(MP_NEXTWILLBEDATA);
fim;
MP_DATA:início
tentar
GetMem(bufSend,iBYTEPERSEND+1);
if (fsSend.Position+1+iBYTEPERSEND) <fsSend.Size então
começar
fsSend.Read(bufSend^,iBYTEPERSEND);
Socket.SendBuf(bufSend^,iBYTEPERSEND);
fsSend.Free;
end // Envio normal, o tamanho é iBYTEPERSEND
senão começar
fsSend.Read(bufSend^,fsSend.Size-fsSend.Position-1);
Socket.SendBuf(bufSend^,fsSend.Size-fsSend.Position-1);
end; //A última vez que enviar, envia os dados restantes
finalmente
FreeMem(bufSend,iBYTEPERSEND+1);
fim;{de tentativa}
fim;
MP_ABORT:início
//Cancelado :(
fsSend.Free;
fim;
fim;{do caso}
fim;
Procedimento de organização:
Adicione julgamento de erro, otimize o programa, combine o servidor e o cliente, adicione a exibição do progresso do tempo restante, possibilite a transferência de vários arquivos ao mesmo tempo e adicione uma função de bate-papo, e torna-se uma boa transferência de arquivos ponto a ponto programa.