A transferência de
arquivos usando sockets na linguagem C# é um
processo Cliente-Servidor com certo grau de complexidade. Podemos
dividir esse
processo em três fases:
|
O que é um socket ?
Um socket pode ser entendido como uma porta de um canal de comunicação que permite a um processo executando em um computador enviar/receber mensagens para/de outro processo que pode estar sendo executado no mesmo computador ou num computador remoto.
Os sockets permitem então a comunicação processo a processo da seguinte forma :
comunicação local : processos locais usando sockets locais
comunicação remota : processos remotos usando sockets em rede (TCP/IP)
Abaixo temos uma figura com que representa a comunicação de sockets e a pilha TCP/IP:
Tipos de serviço
de transporte:
|
Paradigma cliente/servidor (modo orientado a conexão )
Para completar a transferência de dados entre o cliente e o servidor temos a seguinte sequência de ações realizadas no paradigma cliente/servidor:
Servidor | Cliente |
1- Cria um IP End Point(endereço IP e Porta) e um objeto Socket e então vincula o objeto socket com o IP End Point e envia-o para o modo listen para aguardar a conexão do cliente | |
2- Cria um IP End Point(endereço IP e Porta) e um objeto socket | |
3- Prepara os dados do arquivo (em bytes) a ser enviado | |
4- Tentar se conectar com o servidor usando socket cliente com ajuda do IP End Point | |
5. Recebe a solicitação do cliente e aceita. Uma vez que a conexão esteja estabelecida, o servidor cria um outro objeto soquete que irá lidar com este cliente até que todos os pedidos de conexão terminem. O Cliente será informado internamente pelo TCP sobre o sucesso de conexão. | |
6. Inicia os preparativos para armazenar os bytes que chegam do cliente | |
7- Inicia o envia dos bytes dos dados sobre o socket conectado. | |
8- Recebe os bytes do arquivo de dados junto com o nome do arquivo e os armazena em um array de bytes | |
9- Obtém o nome do arquivo a partir dos bytes de dados recebidos | |
10- Abre um escritor stream binário com o nome do arquivo para armazenar os bytes de dados | |
11- Após salvar o arquivo, fecha o escritor stream binário e os objetos sockets do servidor | |
12- Uma vez que a transferência esteja terminada e o servidor fechou a conexão via socket o cliente também fecha o objeto socket | |
13 - O programa do lado do servidor é encerrado | |
14 - O programa do lado cliente é encerrado. |
Objetivo
Transferir arquivos de pequeno tamanho em um ambiente de rede usando sockets e o paradigma cliente/servidor. Usar os recursos da classe Socket do namespace System.NET.
Recursos usados:
Criando o projeto Cliente
Abra o Visual Studio 2013 Express for Windows Desktop e clique em New Project;
Selecione a linguagem Visual C# e o template Windows Forms Application e informe o nome Socket_Cliente;
A seguir inclua no formulário form1.cs criado por padrão os seguintes controles:
A seguir disponha os controles no formulário conforme o leiaute da figura abaixo:
No menu PROJECT clique em Add Class e informe o nome FTCliente.cs e a seguir digite o código abaixo nesta classe:
using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace Socket_Cliente
{
public class FTCliente
{
public static string mensagemCliente = "em espera";
public static void EnviarArquivo(string nomeArquivo)
{
try
{
string strEnderecoIP = "192.168.1.11";
IPEndPoint ipEnd_cliente = new IPEndPoint(IPAddress.Parse(strEnderecoIP), 5656);
Socket clientSock_cliente = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
string caminhoArquivo = "";
nomeArquivo = nomeArquivo.Replace("\\", "/");
while (nomeArquivo.IndexOf("/") > -1)
{
caminhoArquivo += nomeArquivo.Substring(0, nomeArquivo.IndexOf("/") + 1);
nomeArquivo = nomeArquivo.Substring(nomeArquivo.IndexOf("/") + 1);
}
byte[] nomeArquivoByte = Encoding.UTF8.GetBytes(nomeArquivo);
if (nomeArquivoByte.Length > 5000 * 1024)
{
mensagemCliente = "O tamanho do arquivo é maior que 5Mb, tente um arquivo menor.";
return;
}
string caminhoCompleto = caminhoArquivo + nomeArquivo;
byte[] fileData = File.ReadAllBytes(caminhoCompleto);
byte[] clientData = new byte[4 + nomeArquivoByte.Length + fileData.Length];
byte[] nomeArquivoLen = BitConverter.GetBytes(nomeArquivoByte.Length);
nomeArquivoLen.CopyTo(clientData, 0);
nomeArquivoByte.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + nomeArquivoByte.Length);
clientSock_cliente.Connect(ipEnd_cliente);
clientSock_cliente.Send(clientData, 0, clientData.Length, 0);
clientSock_cliente.Close();
mensagemCliente = "Arquivo [" + caminhoCompleto + "] transferido.";
}
catch (Exception ex)
{
mensagemCliente = ex.Message + " " +"\nFalha, pois o Servidor não esta atendendo....";
}
}
}
}
|
Entendendo o código:
-Definindo um endereço IP da máquina local
string strEnderecoIP = "192.168.1.11";
- Criando um IPEndPoint com o endereço IP e uma porta
IPEndPoint ipEnd_cliente = new IPEndPoint(IPAddress.Parse(strEnderecoIP), 5656);
- Criando um objeto Socket usando uma família de endereços e definindo o tipo de
soquete como stream que oferece suporte a fluxos de bytes bidirecional
Socket clientSock_cliente = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
Nota: Antes de um Socket poder enviar e receber dados, ele primeiro deve ser criado usando um AddressFamily, um SocketTypee um ProtocolType. A enumeração SocketType fornece várias opções para definir o tipo de Socket que se pretende abrir.
Depois de ler o arquivo e criar um fluxo de bytes realizamos a conexão com o servidor usando o método Connect e a seguir enviamos os dados de forma assíncrona com o método Send.
clientSock_cliente.Connect(ipEnd_cliente);
clientSock_cliente.Send(clientData, 0, clientData.Length, 0);
clientSock_cliente.Close();
O método Send usado envia o número de bytes ao socket conectado, a partir do deslocamento especificado e usando o SocketFlags definido.
Agora no formulário form1.cs inclua no evento Click do botão de comando btnEnviar o código abaixo:
private void btnEnviar_Click(object sender, EventArgs e)
{
try
{
FTCliente.EnviarArquivo(txtArquivo.Text);
lbmsgCliente.Items.Add(FTCliente.mensagemCliente);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
|
Este código utiliza o método EnviarArquivo() da classe FTCliente, que é um método estático, para enviar o arquivo informado na caixa de texto. Depois preenche o controle ListBox com a mensagem retornada.
Criando o projeto Servidor
Abra o Visual Studio 2013 Express for Windows Desktop e clique em New Project;
Selecione a linguagem Visual C# e o template Windows Forms Application e informe o nome Socket_Servidor;
A seguir inclua no formulário form2.cs criado por padrão os seguintes controles:
A seguir disponha os controles no formulário conforme o leiaute da figura abaixo:
No menu PROJECT clique em Add Class e informe o nome FTServidor.cs e a seguir inclua o código abaixo nesta classe:
using System; using System.Text; using System.Net; using System.Net.Sockets; using System.IO; namespace Socket_Servidor public static void IniciarServidor() try byte[] dadosCliente = new byte[1024 * 50000]; int tamanhoBytesRecebidos = clienteSock.Receive(dadosCliente, dadosCliente.Length, 0); BinaryWriter bWrite = new BinaryWriter(File.Open(caminhoRecepcaoArquivos + nomeArquivo, FileMode.Append)); clienteSock.Close(); |
Entendendo o código:
- Define o local onde os arquivos serão recebidos e salvos
public static string caminhoRecepcaoArquivos = @"M:\";
- Define o IP do servidor
string strEnderecoIP = "192.168.1.11";
-
Cria um IPEndPoint
usando o IP , e a porta onde o servidor estará escutando:
ipEnd_servidor = new IPEndPoint(IPAddress.Parse(strEnderecoIP), 5656);
- Cria um objeto
Socket usando uma família de endereços e definindo o tipo de soquete como stream
que oferece suporte a fluxos de bytes bidirecional
sock_Servidor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
- Associa o socket ao
EndPoint criado. Devemos usar um Bind antes de chamar o Listen.
sock_Servidor.Bind(ipEnd_servidor);
- Coloca o socket em estado de escuta a espera da requisição do cliente indicando o número de conexões de entrada que podem ser colocadas na fila como igual a 100
sock_Servidor.Listen(100);
- Cria o novo socket para a conexão ativa a partir da conexões que estão na fila
Socket clienteSock = sock_Servidor.Accept();
- Define o tamanho do buffer de
recebimento do socket
clienteSock.ReceiveBufferSize = 16384;
- Recebe o número de bytes especificado de dados de Socket vinculado em um buffer de recebimento, usando SocketFlags definido.
int tamanhoBytesRecebidos = clienteSock.Receive(dadosCliente, dadosCliente.Length, 0);
Nota: Lembre-se que os
métodos Send e Receive da classe Sockect pela definição não são obrigados a realmente enviar/receber
todos os dados que você forneceu. O valores estão limitados ao buffer internos do sistema que estão relacionados com a placa de rede. O tamanho limite do buffer interno ou o tamanho máximo de um pacote TCP também afetam os valores enviados e recebidos. (O limite é 8KB por processo) Por isso para ter certeza que os dados foram totalmente enviados/recebidos é recomendado usar laço :
int bytesJaEnviados = arr.Length ; |
No formulário form1.cs vamos também declarar os namespaces usados no projeto:
using System;
using System.Windows.Forms;
A seguir no evento Click do botão de comando btnIniciarServidor inclua o código a seguir:
private void btnIniciarServidor_Click(object sender, EventArgs e)
{
FTServidor.IniciarServidor();
txtStatus.Text = FTServidor.mensagemServidor;
}
|
O código acima usa o método estático IniciarServidor da classe FTServidor para colocar o servidor em atendimento e a seguir exibe a mensagem na caixa de texto.
1,2,3 Testando...
Para testar temos que fazer os seguintes procedimentos:
Ao final desses procedimento devemos obter o seguinte resultado:
Atenção:
Os projetos mostrados neste artigo são bem simples e tem como objetivo mostrar como usar a classe Socket.
Para criar um projeto mais robusto você devera ajustar e melhorar os exemplos para permitir a transferência de vários arquivos e de arquivos com tamanho maior que 5 MB.
Pegue os projetos completos aqui : Socket_Servidor.zip e Socket_Cliente.zip
Filipenses 2:5 Tende em vós aquele sentimento que houve também em Cristo Jesus,
Filipenses 2:6 o qual, subsistindo em forma de Deus, não considerou o ser igual a Deus coisa a que se devia aferrar,
Filipenses 2:7 mas esvaziou-se a si mesmo, tomando a forma de servo, tornando-se semelhante aos homens;
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
|
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#