[Resumo] Os programadores que escreveram aplicativos Winsock sabem que escrever aplicativos Winsock não é uma tarefa fácil. Você não deve lidar diretamente com APIs complexas no Winsock. Felizmente, Tclientsocket e Tserversocket encapsulam as APIs relevantes no Windows. para Winsock, permitindo-nos escrever aplicativos Winsock com muita facilidade. Este artigo apresenta como escrever aplicações Winsock utilizando Delphi através de um exemplo de leitura da tela de outro computador na LAN.
Qualquer pessoa que tenha trabalhado como administrador de rede em um local de trabalho pode ter passado por essa experiência. Como é chato instruir outras pessoas a operar por "controle remoto" pelo telefone. Além disso, sou uma pessoa preguiçosa e não quero fugir. do topo ao fundo do prédio todos os dias para assuntos triviais, o que fazer? Que tal escrever um programa que leia a tela de outro computador? É muito mais intuitivo. Para se comunicar em uma rede local, a melhor opção é usar o Winsock. Os programadores que escreveram aplicativos Winsock sabem que escrever aplicativos Winsock não é uma tarefa fácil. Felizmente, você não deve lidar diretamente com as APIs complexas. , Tclientsocket e Tserversocket no Delphi4 encapsulam as APIs relevantes no Windows, simplificando bastante o acesso ao Winsock, permitindo-nos escrever aplicativos Winsock com muita facilidade. No entanto, é melhor ter algum conhecimento do Winsock. Não entrarei em detalhes aqui. Você pode encontrar alguns livros e lê-los você mesmo.
Para transmitir dados pela rede, você precisa de pelo menos um par de soquetes, um no lado do cliente e outro no lado do servidor. Uma vez conectados, os soquetes do lado do cliente e do servidor podem se comunicar entre si. O soquete é estabelecido em TCP/Baseado em IP, ele também suporta ipx/spx e outros protocolos relacionados. No Delphi, Tclientsocket e Tserversocket são usados para controlar a conexão e a comunicação entre o cliente e o servidor Socket. Deve-se observar que esses dois componentes são utilizados para gerenciar a conexão entre o servidor e o cliente. Eles não são objetos Socket em si. O que controla o objeto Socket é TcustomwinSocket, como Tclientwinsocket, Tserverclientwinsocket e Tserverwinsocket.
1. Componente Tclientsocket:
Ao adicionar um Tclientsocket ao Form, a aplicação se torna um cliente Tcp/ip, e Tclientsocket pode ser usado para manipular o objeto Socket do cliente.
Para estabelecer uma conexão com um servidor, primeiro especifique o servidor ao qual deseja se conectar. Existem duas maneiras de especificar o servidor. Uma é definir o atributo Host para especificar o nome do host do servidor, como http://www.inPRise.com ou o nome da máquina na LAN. requer resolução de nome de domínio, que será um pouco mais rápida. Outro método é definir o atributo Adress para especificar o endereço IP do host, como 130.0.1.1. Os dois métodos são equivalentes, mas se Host e Adress estiverem definidos, o Delphi usará apenas a propriedade Host.
Então você precisa especificar o número da porta para se conectar ao servidor. Uma é definir o serviço para usar o número da porta padrão. A outra é definir diretamente o número da porta abaixo de 1024. , muitos foram alocados, como FTP As portas são 20 e 21, a porta SMTP é 25, a porta do servidor WEB é 80, etc. é melhor definir a porta para 1024 ou superior. Se o serviço e a porta forem definidos ao mesmo tempo, o Delphi usará a porta padrão do serviço.
Após especificar o servidor e o número da porta, chame o método open ou defina o atributo Active como True. O Socket do cliente fará uma solicitação de conexão ao Socket do servidor. Se o servidor estiver no estado de escuta neste momento, ele aceitará automaticamente o. solicitação para estabelecer uma conexão Quando conectado, seu evento Onconnet é acionado. Quando precisar se desconectar, basta chamar o método close ou definir o atributo Active como False. Neste momento, o evento ondisconnet será acionado.
2. Componente Tserversocket:
Assim como o Tclientsocket, para construir um servidor, você só precisa colocar um componente Tserversock no Form.
O objeto soquete do lado do servidor é mais complicado de gerenciar. Quando o servidor está no estado de escuta, o objeto de soquete do servidor é manipulado pelo Tserversocket; quando o cliente faz uma solicitação, o servidor responde à solicitação e estabelece uma conexão. Neste momento, o Tserverclientwinsocket é usado para manipular a conexão entre o servidor. Socket e o Socket do cliente.
Para colocar o servidor no estado de escuta, você deve primeiro especificar o número da porta. Obviamente, deve ser igual ao número da porta do cliente. Em seguida, chame o método open ou defina a propriedade Active como True.
3. Comunicação:
Uma vez estabelecida a conexão entre o cliente e o servidor, a comunicação entre eles pode começar. Delphi fornece vários métodos de comunicação para Tserversocket e Tclientsocket é usado para enviar informações de texto, sendstream é usado para enviar fluxos e SendBuf é usado para enviar dados de comprimento especificado.
Deve-se observar que como o tamanho do buffer padrão do Windows é 4K, ao enviar informações maiores que 4K, por exemplo, um fluxo binário enviado do servidor para o cliente, você só precisa usar Socket.SendStream() no servidor. , mas é diferente no cliente. Ele acionará o evento onread várias vezes e o Delphi não define eventos como "onreadend". Portanto, o próprio programador deve montar os dados ao recebê-los. O método adotado neste artigo é primeiro enviar o comprimento do fluxo ao cliente e, em seguida, enviar o fluxo. O cliente grava os dados recebidos em um fluxo. Quando o comprimento do fluxo é igual ao comprimento enviado de volta pelo servidor, isso indica. que o cliente concluiu o recebimento. Para o servidor, o fluxo usado como parâmetro sendstream será "de propriedade" do Socket. Quando o objeto Socket terminar, ele também será encerrado, caso contrário, uma exceção será acionada.
Da mesma forma, quando o texto enviado for inferior a 4K, por exemplo ao fazer a seguinte chamada no programa cliente
clientesocket1.Socket.SendText('gets');
clientesocket1.Socket.SendText('gets');
clientesocket1.Socket.SendText('gets');
Quando o servidor recebe, fenômenos como getgets aparecerão. Isso pode ocorrer porque, quando os dados no buffer ainda não foram enviados, um novo texto é colocado no buffer e o computador o trata como o mesmo lote de dados para processamento. . Para evitar que esse fenômeno aconteça, você pode usar o método de “jogar a bola” para frente e para trás no programa:
servidor cliente
clientsocket1.Socket.SendText('data1') socket.ReceiveText;
socket.sendtext('ok');
soquete.receivetext;
clientesocket1.Socket.SendText('dados2')
soquete.ReceiveText;
socket.sendtext('fim');
soquete.receivetext;
Depois de executar o programa do servidor em outro computador, digite o nome do computador na caixa de texto do seu programa cliente, clique em “Conectar” e clique em “Obter Imagem”. Você terá uma visão clara da tela do computador da outra parte. A seguir está todo o código-fonte do programa. Este programa pode ser executado em NT4.0, Win95, Win98 e LAN. É claro que o Windows deve ter o protocolo TCP/IP instalado e deve ter um IP atribuído ou especificado dinamicamente. endereço.
Se você achar difícil "comandar" enquanto assiste, você também pode analisar os eventos do teclado e do mouse na imagem1 e, em seguida, enviá-los ao servidor. Após o recebimento, o servidor executará a mesma operação novamente, para que você não. não precisa se preocupar. Usando Tclientsocket e Tserversocket do Delphi, você também pode completar o desenvolvimento de aplicativos como cópia de arquivos, chat online, ICQ, etc.
Programa cliente:
unidade cprincipal;
interface
usa
Windows, Mensagens, SysUtils, Classes, Gráficos, Controles, Formulários, Diálogos,
ScktComp, StdCtrls, ExtCtrls,jpeg;
tipo
TForm1 = classe(TForm)
Painel1: TPanel;
ScrollBox1: TScrollBox;
Imagem1: TImage;
Botão1: Botão T;
Editar1: TEdit;
Botão2: Botão T;
ClienteSocket1: TClientSocket;
Rótulo1: TLabel;
procedimento Button1Click(Remetente: TObject);
procedimento Button2Click(Remetente: TObject);
procedimento ClientSocket1Connect(Remetente: TObject;
Soquete: TCustomWinSocket);
procedimento ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedimento ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedimento FormCreate(Remetente: TObject);
procedimento FormClose(Sender: TObject; var Action: TCloseAction);
privado
{Declarações privadas}
público
{Declarações públicas}
fim;
var
Formulário1: TForm1;
c: inteiro longo;
m:tmemorystream;
implementação
{$R *.DFM}
procedimento TForm1.Button1Click(Remetente: TObject);
começar
tentar
clientesocket1.Close;
clientesocket1.Host:=edit1.text;
clientsocket1.Open; //Conecta-se ao servidor
exceto
showmessage(edit1.text+#13#10+'O computador não está ligado ou o programa de serviço não está instalado');
fim;
fim;
procedimento TForm1.Button2Click(Remetente: TObject);
começar
clientsocket1.Socket.SendText('gets'); //Envia uma solicitação para notificar o servidor que uma imagem de tela é necessária
fim;
procedimento TForm1.ClientSocket1Connect(Remetente: TObject;
Soquete: TCustomWinSocket);
começar
caption:='Conectar a'+edit1.text;
fim;
procedimento TForm1.ClientSocket1Error(Remetente: TObject;
Soquete: TCustomWinSocket; ErrorEvent: TErrorEvent;
varErrorCode: Inteiro);
começar
caption:='Conexão'+edit1.text+'Falha';
showmessage(edit1.text+#13#10+'O computador não está ligado ou o programa de serviço não está instalado');
código de erro:=0;
fim;
procedimento TForm1.ClientSocket1Read(Remetente: TObject;
Soquete: TCustomWinSocket);
var
buffer:array [0..10000] de byte //Definir o buffer de recebimento;
len:inteiro;
ll:string;
b:tbitmap;
j:tjpegimage;
começar
se c=0 então //C é o número de bytes enviados pelo servidor. Se for 0, significa que a recepção da imagem ainda não foi iniciada.
começar
ll:=socket.ReceiveText;
c:=strtoint(ll); //Define o número de bytes a serem recebidos
clientsocket1.Socket.SendText('okok'); //Notifica o servidor para iniciar o envio de imagens
fim mais
começar //A seguir está a parte de recebimento de dados de imagem
len:=socket.ReceiveLength; //Lê o comprimento do pacote
socket.ReceiveBuf(buffer,len); //Recebe o pacote de dados e lê-o no buffer
m.Write(buffer,len); //Anexar ao fluxo M
if m.Size>=c then //Se o comprimento do stream for maior que o número de bytes a serem recebidos, a recepção será concluída
começar
m.Posição:=0;
b:=tbitmap.Create;
j:=tjpegimage.Create;
tentar
j.LoadFromStream(m); //Lê os dados do fluxo M no objeto de imagem JPG J.
b.Assign(j); //Converter JPG em BMP
Image1.Picture.Bitmap.Assign(b); //Atribuir ao elemento image1
finalmente //A seguir está o trabalho de limpeza
b.grátis;
j.grátis;
clientesocket1.Active:=falso;
clientesocket1.Active:=true;
m.Limpar;
c:=0;
fim;
fim;
fim;
fim;
procedimento TForm1.FormCreate(Remetente: TObject);
começar
m:=tmemorystream.Create;
fim;
procedimento TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
começar
m.livre;
ClienteSocket1.Fechar;
fim;
fim.
Programa de servidor:
unidade principal;
interface
usa
Windows, Mensagens, SysUtils, Classes, Gráficos, Controles, Formulários, Diálogos,
ScktComp,jpeg;
tipo
TForm1 = classe(TForm)
ServidorSocket1: TServerSocket;
procedimento ServerSocket1ClientRead(Sender: TObject;
Soquete: TCustomWinSocket);
procedimento FormCreate(Remetente: TObject);
privado
{Declarações privadas}
público
{Declarações públicas}
fim;
var
Formulário1: TForm1;
m1:tmemorystream;
implementação
{$R *.DFM}
procedimento TForm1.ServerSocket1ClientRead(Sender: TObject;
Soquete: TCustomWinSocket);
var
s,s1:string;
mesa: lona;
bitmap:tbitmap;
jpg:tjpegimage;
começar
s:=socket.ReceiveText;
if s='gets' then //O cliente emite uma solicitação
começar
bitmap:=tbitmap.Create;
jpg:=tjpegimage.Create;
desk:=tcanvas.Create; //O código a seguir é para obter a imagem da tela atual
mesa.Handle:=getdc(hwnd_desktop);
m1:=tmemorystream.Create; //Inicializa o stream m1, após enviar o stream com sendstream(m1),
//Permanecerá até que a conversa do soquete termine,
//Não pode ser liberado manualmente, caso contrário uma exceção será acionada
com bitmap faça
começar
largura:=tela.Largura;
altura:=tela.Altura;
canvas.CopyRect(canvas.cliprect,desk,desk.cliprect);
fim;
jpg.Assign(bitmap); //Converte a imagem para o formato JPG
jpg.SaveToStream(m1); //Escreve a imagem JPG no stream
jpg.gratuito;
m1.Posição:=0;
s1:=inttostr(m1.tamanho);
Socket.sendtext(s1); //Enviar tamanho da imagem
fim;
if s='okok' then //O cliente está pronto para receber imagens
começar
m1.Posição:=0;
Socket.SendStream(m1); //Enviar imagem JPG
fim;
fim;
procedimento TForm1.FormCreate(Remetente: TObject);
começar
ServidorSocket1.open;
fim;
fim.