2016-01-13 27 views
6

Sto utilizzando i socket in C# per inviare dati dal server al computer client. In effetti ho creato un catturatore che cattura la corrente kinect da 3 diverse macchine. Voglio generare una comunicazione server e client per inviare il segnale dal server ai dispositivi restanti per iniziare e interrompere il processo di registrazione. Voglio con il tasto sinistro del mouse per inviare un messaggio per iniziare la registrazione e con il tasto destro del mouse per interrompere la registrazione. Il mio codice è il seguente:Invia un flag dal server ai client utilizzando eventi del mouse C#

public Form1() 
{ 
    InitializeComponent(); 
    this.MouseClick += mouseClick1; 


    Thread thread = new Thread(() => StartServer(message)); 
    thread.Start(); // server is begining 
} 

private void mouseClick1(object sender, MouseEventArgs e) 
{ 

    if (e.Button == MouseButtons.Left) 
    { 
     message = "start"; 
     try 
     { 
       obj = new Capturer(dirPath + name + "_" + surname, 20); 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine("The process failed: {0}", e1.ToString()); 
     } 
     if (clientSockets.Count > 0) 
     { 
      Thread.Sleep(10); 
      foreach (Socket socket1 in clientSockets) 
       socket1.Send(Encoding.ASCII.GetBytes(message)); //send everything to all clients as bytes 
     } 
     else 
     { 

      serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client 
     } 

    } 
    else if (e.Button == MouseButtons.Right) 
    { 
     message = "stop"; 
     obj.flag2 = true; 

     if (clientSockets.Count > 0) 
     { 
      Thread.Sleep(10); 
      foreach (Socket socket1 in clientSockets) 
       socket1.Send(Encoding.ASCII.GetBytes(message)); //send everything to all clients as bytes 
     } 
     else 
     { 

      serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client 
     } 
    } 
} 

public void StartServer(String message) { 

    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO)); 
    serverSocket.Listen(4); //the maximum pending client, define as you wish 
    serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); 
    string result = ""; 
    do 
    { 
     result ="asdf"; 
    } while (result.ToLower().Trim() != "exit"); 
} 
private const int BUFFER_SIZE = 4096; 
private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message 
private static List<Socket> clientSockets = new List<Socket>(); //may be needed by you 
private static void acceptCallback(IAsyncResult result) 
{ //if the buffer is old, then there might already be something there... 
    Socket socket = null; 
    try 
    { 

     socket = serverSocket.EndAccept(result); // The objectDisposedException will come here... thus, it is to be expected! 
     //Do something as you see it needs on client acceptance 
     clientSockets.Add(socket); 
     socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); 


     string msg = "start"; 
     //socket.Send(Encoding.ASCII.GetBytes(msg)); 

     if (clientSockets.Count > 0) 
     { 
      Thread.Sleep(10); 
      foreach (Socket socket1 in clientSockets) 
       socket1.Send(Encoding.ASCII.GetBytes(msg)); //send everything to all clients as bytes 
     } 
     else 
     { 

      serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client 
     } 
    } 
    catch (Exception e) 
    { // this exception will happen when "this" is be disposed...   
     //Do something here    
     Console.WriteLine(e.ToString()); 
    } 
} 

const int MAX_RECEIVE_ATTEMPT = 10; 
static int receiveAttempt = 0; //this is not fool proof, obviously, since actually you must have multiple of this for multiple clients, but for the sake of simplicity I put this 
private static void receiveCallback(IAsyncResult result) 
{ 
    Socket socket = null; 
    try 
    { 
     socket = (Socket)result.AsyncState; //this is to get the sender 
     if (socket.Connected) 
     { //simple checking 
      int received = socket.EndReceive(result); 
      if (received > 0) 
      { 
       byte[] data = new byte[received]; //the data is in the byte[] format, not string! 
       Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to http://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest 
       //DO SOMETHING ON THE DATA int byte[]!! Yihaa!! 
       Console.WriteLine(Encoding.UTF8.GetString(data)); //Here I just print it, but you need to do something else      

       //Message retrieval part 
       //Suppose you only want to declare that you receive data from a client to that client 
       string msg = "I receive your message on: " + DateTime.Now; 
       socket.Send(Encoding.ASCII.GetBytes(msg)); //Note that you actually send data in byte[] 
       Console.WriteLine("I sent this message to the client: " + msg); 

       receiveAttempt = 0; //reset receive attempt 
       //socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive 
      } 
      else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) 
      { //fail but not exceeding max attempt, repeats 
       ++receiveAttempt; //increase receive attempt; 
       socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive 
      } 
      else 
      { //completely fails! 
       Console.WriteLine("receiveCallback fails!"); //don't repeat beginReceive 
       receiveAttempt = 0; //reset this for the next connection 
      } 
     } 
    } 
    catch (Exception e) 
    { // this exception will happen when "this" is be disposed... 
     Console.WriteLine("receiveCallback fails with exception! " + e.ToString()); 
    } 
} 

Come posso analizzare la bandiera nel server, al fine di inviare tale valore nei clienti? È possibile modificare qui il tipo statico di funzioni del server? Come è ora il codice inizia il server che invia la stringa "start" ai client. Come posso inviare il messaggio di stringa di una bandiera bool? Il mio problema sta nel tipo statico delle mie funzioni di callback. E 'possibile aggiungere come argomento il messaggio per esempio nel AsyncCallback:

serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); 
+0

Hey, ora si sta utilizzando 'Async' abbastanza bene. ;) grande! – Ian

+0

: P Ho avuto un insegnante così bravo! @Ian è feasibe aggiungere un argomento all'interno dell'AsyncCallback? –

+0

No no, penso che ti stia prendendo in fretta. = D – Ian

risposta

2

In primo luogo, circa l'evento MouseClick. Dal momento che si stanno avendo esclusiva qualificazione per l'evento (cioè, un clic sinistro e un altro tasto destro del mouse), entrambi è possibile combinare in un unico event

public Form1() 
{ 
    InitializeComponent(); 
    this.MouseClick += mouseClick1; //one event is enough 

    Thread thread = new Thread(() => StartServer(message)); 
    thread.Start(); // server is begining 
} 

private void mouseClick1(object sender, MouseEventArgs e) 
{ 
    if (e.Button == MouseButtons.Left) 
    { 
     try 
     { 
      obj = new Capturer(dirPath + name + "_" + surname, 20); //captures the kinect streams 
     } 
     catch (Exception e1) 
     { 
      Console.WriteLine("The process failed: {0}", e1.ToString()); 
     } 
    } 
    else if (e.Button == MouseButtons.Right) 
    { 
     obj.flag2 = true; // flag that handle the recording, true value stops the recording, possible I want that value to be send to the client in order the same thing happen. 
    } 
} 

e sta andando ad essere ok.

Avanti, rispondere alle vostre domande:

D: Come posso analizzare la bandiera nel server, al fine di trasmettere tale valore nei client?

A: nel vostro evento mouseClick1, è sufficiente utilizzare sync di invio che fate nella vostra accept callback, cambiare il msg con qualcos'altro (diciamo byte[] val = new byte[] { 1 };)

foreach (Socket socket1 in clientSockets) //Do this in your `if (e.Button == Mouse.Left and Mouse.Right) blocks 
    socket1.Send(Encoding.ASCII.GetBytes(msg)); 

D: E 'possibile cambiare qui il tipo static delle funzioni del server?

A: Sì, sicuramente! è windows form, non è necessario utilizzare il tipo static affatto! A differenza del Console App nella tua domanda precedente. Vorrei anche suggerire di fare nulla static quando possibile

D: Come è ora il codice inizierà il server che inviano solo la stringa "start" al clients. Come posso inviare il messaggio string di un flag ?

A: dal momento che si utilizza socket, non è possibile davvero inviare il flag bool in modo da parlare a . Ti invieremo byte[]. Ma puoi sempre verificare l'implementazione del tuo client . Se lo byte[] ha un determinato valore, semplicemente cambialo in bool. Ad esempio, si consideri di inviare solo 1 o 0 dal proprio server.Poi, nel tuo client endReceiveCallback, si potrebbe semplicemente controllare il data venire e vedere se è 1 allora è true, e se è 0 allora è false

D: Il mio problema sta nel static tipo di mia funzioni di callback. È possibile aggiungere come argomento il messaggio per esempio nel AsyncCallBack

A: questo è winform, si potrebbe sbarazzarsi di tutti static var! E sì, passalo come sostituto di null nel tuo Begincallback. Poi si passa anche l'oggetto.

//Change null with something else 
serverSocket.BeginAccept(new AsyncCallback(acceptCallback), myobj); 

Poi, nel tuo acceptCallback, prendete il vostro oggetto utilizzando la IAsyncResult.AsyncState

+1

In ogni caso, cerca di capirlo usando la risposta che ho postato. ;) non è difficile, davvero. Spiacenti, potrebbe essere necessario eseguire prima il debug del mio codice, potrebbe non rispondere rapidamente ai tuoi commenti successivi. Attualmente ho questo problema: http://stackoverflow.com/questions/34767669/same-code-but-different-results-in-windows-form-and-in-windows-service-during-s – Ian

+0

Sì, tuttavia client sembra accettare un messaggio alla volta. Voglio dire se non cambia con il secondo clic. –

+0

Inizializzo una variabile di messaggio e in accettazione callback lo invio al client. Inoltre ho il codice foreach all'interno dei pulsanti. Solo la variabile di inizializzazione viene inviata al client. –