2015-03-21 1 views
-1

Je crée une application de chat client/serveur en utilisant les classes TcpClient et TcpListener. Il devrait être capable de transférer des messages texte et des fichiers entre le client et le serveur. Je suis capable de gérer les messages texte en créant un thread pour chaque client séparé, puis en créant un thread secondaire pour recevoir le message principal qui crée le thread principal réservé à l'envoi de messages. Maintenant, si je serais capable d'identifier ce message entrant est un fichier et non un message texte, je sais comment le gérer en utilisant NetworkStream et FileStream. Mais je suis incapable de le faire. Le code pour gérer le fichier entrant est here. Aussi s'il vous plaît dites-moi s'il y a des limitations en utilisant NetworkStream pour FTP.Identifier un fichier entrant via NetworkStream C#

+0

On dirait que vous devez mettre le type de message dans le protocole, essentiellement ... un en-tête pour chaque message spécifiant la longueur du message (en octets - et non en caractères pour les messages texte) et tapez. –

+0

Je ne sais pas comment spécifier le type de message. Y at-il une surcharge de NetworkStream.Read et NetworkStream.Write qui pourrait faire cela? En fait, je suis nouveau au réseautage, s'il vous plaît aidez-moi à le comprendre. @JonSkeet –

+0

Non, vous devez concevoir le protocole pour inclure cette information. Ce n'est pas spécifique aux flux réseau ou à .NET - il s'agit de concevoir le format des données. –

Répondre

1

Réponse: Construisez votre propre protocole. En construisant votre propre protocole de communication, vous pouvez contrôler tous les flux de données/messages.

Par exemple;
1 utilisateur souhaite envoyer un fichier au serveur
2-Client envoie une commande pour informer le serveur qu'il enverra un fichier.
@[email protected];filesize;
3-serveur envoie un message au client prêt Retour @[email protected] 4-serveur commence à écouter les paquets tampons et quand il les reçoit écrit à un flux.
5-Lorsque le client reçoit {@[email protected]} commande commence à envoyer des packages au serveur. Assurez-vous que leurs tailles de tampon sont les mêmes.
6 Lorsque tous les octets complet client envoie @[email protected] dans un tampon diffrent (i utilise 256 pour les commandes et 1024 pour le transfert de fichiers)
7 Lorsque le serveur reçoit la commande de 256 octets regarde si sa la commande @[email protected] et flux fichier de véritables bouffées et ferme connexion.

Je ne vous recommande d'utiliser Async

écouter les connexions sur le serveur comme celui-ci

server.BeginAcceptTcpClient(ServerAcceptEnd,server); 

Et lorsqu'une connexion est présente

public void ServerAcceptEnd(IAsyncResult ar) 
{ 
    if(!ar.IsCompleted) 
    { 
     //Something went wrong 
     AcceptServer(); 
     return; 
    } 
    try 
    { 
     var cli = servertc.EndAcceptTcpClient(ar); 
     if(cli.Connected) 
     { 
      //Get the first Command 
      cli.GetStream().BeginRead(serverredbuffer,0,serverredbuffer.Length,ServerFirstReadEnd,cli); 
     } 
     else 
     { 
      //Connection was not successfull log and wait 
      AcceptServer(); 
     } 
    } 
    catch(Exceiption ex) 
    { 
     //An error occur log and wait for new connections 
     AcceptServer(); 
    } 
} 

Lors de la première commande reçue;

public void ServerFirstReadEnd(IAsyncResult ar) 
    { 
    if(!ar.IsCompleted) 
    { 
     //Something went wrong 
     AcceptServer(); 
     return; 
    } 
     try 
     { 
      TcpClient cli = (TcpClient)ar.AsyncState; 
      int read = cli.GetStream().EndRead(ar); 
      string req = toString(serverredbuffer); 
      if(req.StartsWith("@[email protected]")) 
      { 
       //File Received 
       string filename = req.Replace("@[email protected]",""); 
       string[] spp = filename.Split(';'); 
       filename = spp[0]; 
       serverreceivetotalbytes = Convert.ToInt64(spp[1]); 
       cli.GetStream().Write(toByte("@[email protected]",256),0,256); 
       cli.GetStream().BeginRead(serverreceivebuffer,0,1024,ServerReadFileCyle,cli) 
      } 
      else 
      { 
       //Message Received 
      } 
     } 
     catch(Exception ex) 
     { 
      //An error occur log and wait for new connections 
      AcceptServer(); 
     } 
    } 

Méthode de réception de fichier;

public void ServerReadFileCyle(IAsyncResult ar) 
    { 
     TcpClient cli = (TcpClient)ar.AsyncState; 
     if(ar.IsCompleted) 
     { 
      int read = cli.GetStream().EndRead(ar); 
      if(read == 256) 
      { 
       try 
       { 
        string res = toString(serverreceivebuffer); 
        if(res == "@[email protected]") 
         read = 0; 
       } 
       catch 
       { 
       } 
      } 
      if(read > 0) 
      { 
       serverfile.Write(serverreceivebuffer,0,read); 
       cli.GetStream().BeginRead(serverreceivebuffer,0,1024,ServerReadFileCyle,cli); 
      } 
      else 
      { 
       serverfile.Flush(); 
       serverfile.Dispose(); 
       AcceptServer(); 
      } 
     } 
    } 

Cette partie était coté serveur. Et pour le client;

Lors de l'envoi d'un fichier, envoyez d'abord une information au serveur pour le fichier, puis attendez une réponse du serveur.

try 
{ 
    System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog(); 
    ofd.Multiselect = false; 
    ofd.FileName=""; 
    if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) 
    { 
     filesendpath = ofd.FileName; 
     senderfilestream = System.IO.File.Open(filesendpath,System.IO.FileMode.Open); 
     sendertotalbytes = senderfilestream.Length; 
     filesendcommand = "@[email protected]" + System.IO.Path.GetFileName(filesendpath) + ";" + senderfilestream.Length; 
     senderfilestream.Position = 0; 
     sendertc.BeginConnect(ip.Address,55502,FileConnect,null); 
    } 
    else 
    { 
     //No file selected 
    } 

} 
catch(Exception ex) 
{ 
    //Error connecting log the error 
} 

Si la connexion est réussie, envoyez la commande file et attendez la réponse;

public void FileConnect(IAsyncResult ar) 
    { 
     if(ar.IsCompleted) 
     { 
      sender.EndConnect(ar); 
      if(sender.Connected) 
      { 
       sender.GetStream().Write(toByte(filesendcommand,256),0,256); 
       sender.GetStream().BeginRead(ComputerNameBuffer,0,256,FileSendCyleStarter,null); 

      } 
     } 
    } 

Lorsque la réponse reçue regarde si elle est acceptée;

public void FileSendCyleStarter(IAsyncResult ar) 
    { 
     if(ar.IsCompleted) 
     { 
      if(sender.Connected) 
      { 
       string kabul = toString(ComputerNameBuffer); 
       if(kabul == "@[email protected]") 
       { 
        senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null); 
       } 
      } 
     } 
    } 

L'envoi d'un fichier comporte trois étapes;
1 Lire un morceau pour un démarrage
2 Envoyez ensuite le morceau à server.if son envoi @ terminé FileEnd commande @ et sauter l'étape 3 3 Lire la suite morceau de fichier
étape 4 Retour 2 si le fichier isnt terminée

Etape 1:

senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null); 

Étape 2-4:

public void FileSendCyle(IAsyncResult ar) 
    { 
     if(ar.IsCompleted) 
     { 
      if(sendertc.Connected) 
      { 
       int read = senderfilestream.EndRead(ar); 
       if(read > 0) 
       { 
        sendertc.GetStream().BeginWrite(filesendbuffer,0,read,FileSendCyle2,null); 

       } 
       else 
       { 

        sendertc.GetStream().Write(toByte("@[email protected]",256),0,256); 

       } 
      } 
     } 
    } 

Etape 3:

0 .
public void FileSendCyle2(IAsyncResult ar) 
    { 
     if(ar.IsCompleted) 
     { 
      if(sendertc.Connected) 
      { 
       sendertc.GetStream().EndWrite(ar); 
       senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null); 
      } 
     } 
    } 

Dans abowe exemple, il existe deux méthodes appelées toString() et toByte() Je les ai utilisés pour convertir des chaînes en octets et octets à strings.Here sont eux;

public string toString(byte[] buffer) 
    { 
     return Encoding.UTF8.GetString(buffer).Replace("\0",""); 
    } 
    public byte[] toByte(string str,int bufferlenght) 
    { 
     byte[] buffer = new byte[256]; 
     Encoding.UTF8.GetBytes(str,0,str.Length,buffer,0); 
     return buffer; 
    } 

Le code abowe exemple est pas parfait et ont besoin de beaucoup de la gestion des erreurs et de flux controls.I écrire theese pour vous donner une idée et un début de saut.

L'espoir d'une partie de celui-ci aide à tout le monde^_^

+0

quel est le ** type de variable ** "filesendcommand" –