Search Unity

TcpListener / TcpClient => Just one client ? How to get multi client

Discussion in 'Scripting' started by Pulsar19, Apr 27, 2018.

  1. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hello guys,

    I am working about a Jukebox with a voting system.
    I try to allow several clients to connect to my jukebox (in my PC) so that they can vote for the music of their choice.
    I used TcpListener and Tcpclient because I had problems with UnityNetwork ...
    But I can get one client at a time and I can not change the code to allow multiple connections from different phone / pc clients.
    My code is very badly coded, I know ... Unity crash often. If anyone knows why (at the same time), it would be beautiful.
    (My Server : I get all musics(.wav) from my folder and I create list to play. After I send my list (string) to client and the client will choose the music (string) + send to server.)
    Here is my whole code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.Networking;
    6. using UnityEngine.Networking.NetworkSystem;
    7. using UnityEngine.Audio;
    8. using System.IO;
    9. using System.Threading;
    10. using System.Net.Sockets;
    11. using System.Net;
    12. using System;
    13. using System.Text;
    14.  
    15. [RequireComponent(typeof(AudioSource))]
    16. public class MusicCode : MonoBehaviour
    17. {
    18.  
    19.     public GameObject itemPrefab;
    20.  
    21.     public AudioSource source;
    22.  
    23.     public List<AudioClip> clips = new List<AudioClip>();
    24.     public Slider TimerGraphique;
    25.  
    26.     public Text clipTitre;
    27.     public Text clipActuelTime;
    28.     public Text clipTotalTime;
    29.  
    30.     private int MusicLongueur;
    31.     private int playTimer;
    32.     private int secondes;
    33.     private int minutes;
    34.     private int numbermusic=0;
    35.     WWW url;
    36.  
    37.    
    38.     static string path = "C:/Users/Pulsar/OneDrive/Projects";
    39.     string[] fileList = Directory.GetFiles(path, "*.wav", SearchOption.TopDirectoryOnly);
    40.     string listSongsNames;
    41.     AudioClip musicAJouer;
    42.  
    43.     private string msg = null;
    44.  
    45.  
    46.     #region private members    
    47.     /// <summary>    
    48.     /// TCPListener to listen for incomming TCP connection    
    49.     /// requests.    
    50.     /// </summary>    
    51.     private TcpListener tcpListener;
    52.     /// <summary>
    53.     /// Background thread for TcpServer workload.    
    54.     /// </summary>    
    55.     private Thread tcpListenerThread;
    56.     /// <summary>    
    57.     /// Create handle to connected tcp client.    
    58.     /// </summary>    
    59.     private TcpClient connectedTcpClient;
    60.     #endregion
    61.  
    62.  
    63.  
    64.     void Start()
    65.     {
    66.         source = GetComponent<AudioSource>();
    67.         TimerGraphique.enabled = false; //j'empêche de toucher le slider
    68.         GameObject container = GameObject.Find("Elements");
    69.         // --------------------------
    70.         /*NetworkServer.Listen(25000);
    71.         NetworkServer.RegisterHandler(888, ServerReceiveMessage);*/
    72.         tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests));
    73.         tcpListenerThread.IsBackground = true;
    74.         tcpListenerThread.Start();
    75.        
    76.  
    77.  
    78.         foreach (string chemin in fileList)
    79.         {
    80.             Debug.Log(chemin.Replace(path, "").Replace(".wav", ""));
    81.             GameObject item = Instantiate(itemPrefab) as GameObject;
    82.             item.name = Path.GetFileNameWithoutExtension(chemin);
    83.             item.GetComponentInChildren<Text>().text = Path.GetFileNameWithoutExtension(chemin);
    84.             listSongsNames += Path.GetFileNameWithoutExtension(chemin) + ";";
    85.             item.transform.parent = container.transform;
    86.         }
    87.  
    88.         playMusic(numbermusic);
    89.  
    90.         // --------------------------
    91.  
    92.  
    93.     }
    94.    
    95.     private void playMusic(int i)
    96.     {
    97.         WWW url = new WWW("file://" + fileList[i]);
    98.         musicAJouer = url.GetAudioClip(false);
    99.         while (musicAJouer.loadState != AudioDataLoadState.Loaded){}
    100.         musicAJouer.name = Path.GetFileNameWithoutExtension(fileList[i]);
    101.         Play(musicAJouer);      
    102.     }
    103.  
    104.     IEnumerator WaitMusicEnd()
    105.     {
    106.      
    107.         while (source.isPlaying)
    108.         {
    109.             TimerGraphique.value += Time.deltaTime;
    110.             if (TimerGraphique.value >= musicAJouer.length) // && numbermusic < fileList.Length
    111.             {
    112.                 numbermusic++;
    113.                 numbermusic = numbermusic % fileList.Length;      
    114.                 Nextt(musicAJouer, numbermusic);
    115.             }
    116.             playTimer = (int)source.time;
    117.             yield return null;
    118.         }
    119.         numbermusic++;
    120.         numbermusic = numbermusic % fileList.Length;
    121.         Nextt(musicAJouer, numbermusic);
    122.     }
    123.  
    124.  
    125.  
    126.     public void Play(AudioClip music)
    127.     {
    128.      
    129.         source.clip = music;
    130.         TimerGraphique.maxValue = music.length;
    131.         TimerGraphique.value = 0;
    132.         source.Play();
    133.         ShowTitreClip(numbermusic);
    134.         ShowPlayTime(music);
    135.         StartCoroutine("WaitMusicEnd");
    136.  
    137.     }
    138.  
    139.     public void Nextt(AudioClip music, int k)
    140.     {
    141.         source.Stop();
    142.         StopCoroutine("WaitMusicEnd");
    143.         music.UnloadAudioData();
    144.         playMusic(k);
    145.      
    146.     }
    147.  
    148.     void ShowTitreClip(int k)
    149.     {
    150.         clipTitre.text = Path.GetFileNameWithoutExtension(fileList[k]);
    151.     }
    152.  
    153.     void ShowPlayTime(AudioClip music)
    154.     {
    155.         MusicLongueur = (int)music.length;
    156.         secondes = playTimer % 60;
    157.         minutes = (playTimer / 60) % 60;
    158.         clipTotalTime.text = ((MusicLongueur / 60) % 60) + ":" + (MusicLongueur % 60).ToString("D2");
    159.         clipActuelTime.text = minutes + ":" + secondes.ToString("D2");
    160.     }
    161.  
    162.  
    163.     /// <summary>    
    164.     /// Runs in background TcpServerThread; Handles incomming TcpClient requests    
    165.     /// </summary>    
    166.     private void ListenForIncommingRequests()
    167.     {
    168.         try
    169.         {
    170.             // Create listener on localhost port 8052.            
    171.             tcpListener = new TcpListener(IPAddress.Parse("172.30.40.19"), 8052);
    172.             tcpListener.Start();
    173.             Debug.Log("Server is listening");
    174.             Byte[] bytes = new Byte[1024];
    175.             while (true)
    176.             {
    177.                 using (connectedTcpClient = tcpListener.AcceptTcpClient())
    178.                 {
    179.                     // Get a stream object for reading                    
    180.                     using (NetworkStream stream = connectedTcpClient.GetStream())
    181.                     {
    182.                         int length;
    183.                         // Read incomming stream into byte arrary.                        
    184.                         while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    185.                         {
    186.                             var incommingData = new byte[length];
    187.                             Array.Copy(bytes, 0, incommingData, 0, length);
    188.                             // Convert byte array to string message.                            
    189.                             string clientMessage = Encoding.ASCII.GetString(incommingData);
    190.                             Debug.Log(clientMessage);
    191.                             msg = clientMessage;
    192.                         }
    193.                     }
    194.                 }
    195.             }
    196.         }
    197.         catch (SocketException socketException)
    198.         {
    199.             Debug.Log("SocketException " + socketException.ToString());
    200.         }
    201.     }
    202.     /// <summary>    
    203.     /// Send message to client using socket connection.    
    204.     /// </summary>    
    205.     private void SendMessage()
    206.     {
    207.         if (connectedTcpClient == null)
    208.         {
    209.             return;
    210.         }
    211.  
    212.         try
    213.         {
    214.             // Get a stream object for writing.            
    215.             NetworkStream stream = connectedTcpClient.GetStream();
    216.             if (stream.CanWrite)
    217.             {
    218.                 //string serverMessage = "This is a message from your server.";
    219.                 // Convert string message to byte array.                
    220.                 byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(listSongsNames);
    221.                 // Write byte array to socketConnection stream.              
    222.                 stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    223.                 Debug.Log("Server send");
    224.             }
    225.         }
    226.         catch (SocketException socketException)
    227.         {
    228.             Debug.Log("Socket exception: " + socketException);
    229.         }
    230.     }
    231.  
    232.  
    233.     // Update is called once per frame
    234.     void Update()
    235.     {
    236.        
    237.         if (Input.GetKeyDown(KeyCode.Space))
    238.         {
    239.             SendMessage();
    240.         }
    241.         if (msg != null)
    242.         {
    243.             switch (msg)
    244.             {
    245.                 case "connected":
    246.                     SendMessage();
    247.                     msg = null;
    248.                     break;
    249.                 default:
    250.                     Debug.Log(msg);
    251.                     msg = null;
    252.                     break;
    253.             }
    254.         }
    255.     }
    256.  
    257.  
    258. }
    259.  
    (My Client : Receive list string and create list (with UI). The client will choose the music and and send the title.)

    Code (CSharp):
    1. using System.Net.Sockets;
    2. using System.Threading;
    3. using System;
    4. using System.Text;
    5. using UnityEngine.UI;
    6.  
    7. public class Client : MonoBehaviour
    8. {
    9.     public GameObject itemPrefab;
    10.  
    11.     private GameObject container;
    12.     private GameObject item;
    13.     String[] musics = null;
    14.     private bool pooled = false;
    15.    // static NetworkClient client;
    16.     #region private members    
    17.     private TcpClient socketConnection;
    18.     private Thread clientReceiveThread;
    19.     private string serverMessage = "";
    20.     #endregion
    21.  
    22.     void OnGUI()
    23.     {
    24.         string ipaddress = Network.player.ipAddress;
    25.         GUI.Box(new Rect(10, Screen.height - 50, 100, 50), ipaddress);
    26.  
    27.         if (GUI.Button(new Rect(10, 10, 250, 250), "TOUCH"))
    28.         {
    29.             SendMsg("Hello");
    30.         }
    31.     }
    32.  
    33.     // Use this for initialization
    34.     void Start()
    35.     {
    36.         container = GameObject.Find("Elements");
    37.         ConnectToTcpServer();
    38.        // client = new NetworkClient();
    39.     }
    40.  
    41.     private void Update()
    42.     {
    43.         if (musics != null && musics.Length > 0 && pooled == false)
    44.         {
    45.             Debug.Log("Got musics");
    46.             foreach (string music in musics)
    47.             {
    48.                 Debug.Log(music);
    49.                 item = Instantiate(itemPrefab);
    50.                 item.SetActive(true);
    51.                 item.name = music;
    52.                 Text txt = item.GetComponentInChildren<Text>();
    53.                 txt.text = music;
    54.                 Button itemBtn = item.GetComponent<Button>();
    55.                 itemBtn.onClick.AddListener(() => SendMusic(txt));
    56.                 item.transform.parent = container.transform;
    57.             }
    58.             pooled = true;
    59.         }
    60.     }
    61.  
    62.     /// <summary>    
    63.     /// Setup socket connection.    
    64.     /// </summary>    
    65.     private void ConnectToTcpServer()
    66.     {
    67.         try
    68.         {
    69.             clientReceiveThread = new Thread(new ThreadStart(ListenForData));
    70.             clientReceiveThread.IsBackground = true;
    71.             clientReceiveThread.Start();
    72.             SendMsg("connected");
    73.             Debug.Log("Client is listening");
    74.         }
    75.         catch (Exception e)
    76.         {
    77.             Debug.Log("On client connect exception " + e);
    78.         }
    79.     }
    80.     /// <summary>    
    81.     /// Runs in background clientReceiveThread; Listens for incomming data.    
    82.     /// </summary>    
    83.     private void ListenForData()
    84.     {
    85.         try
    86.         {
    87.             socketConnection = new TcpClient("172.30.40.19", 8052); //172.30.40.19
    88.             Byte[] bytes = new Byte[1024];
    89.             while (true)
    90.             {
    91.                 // Get a stream object for reading                
    92.                 using (NetworkStream stream = socketConnection.GetStream())
    93.                 {
    94.                     int length;
    95.                     // Read incomming stream into byte arrary.                    
    96.                     while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    97.                     {
    98.                         var incommingData = new byte[length];
    99.                         Array.Copy(bytes, 0, incommingData, 0, length);
    100.                         // Convert byte array to string message.                        
    101.                         serverMessage = Encoding.ASCII.GetString(incommingData);
    102.  
    103.                         Debug.Log(serverMessage);
    104.                         //TextList.text = serverMessage;
    105.                         String value = serverMessage;
    106.                         Char delimiter = ';';
    107.                         musics = value.Split(delimiter);
    108.                     }
    109.                  
    110.                 }
    111.             }
    112.  
    113.         }
    114.         catch (SocketException socketException)
    115.         {
    116.             Debug.Log("Socket exception: " + socketException);
    117.         }
    118.     }
    119.  
    120.     private void SendMsg(string msg)
    121.     {
    122.         if (socketConnection == null)
    123.         {
    124.             return;
    125.         }
    126.         try
    127.         {
    128.             // Get a stream object for writing.            
    129.             NetworkStream stream = socketConnection.GetStream();
    130.             if (stream.CanWrite)
    131.             {
    132.                 string clientMessage = msg;
    133.                 // Convert string message to byte array.                
    134.                 byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
    135.                 // Write byte array to socketConnection stream.                
    136.                 stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
    137.                 Debug.Log("Le client a envoyé son message - cela devrait être reçu par le serveur");
    138.             }
    139.         }
    140.         catch (SocketException socketException)
    141.         {
    142.             Debug.Log("Socket exception: " + socketException);
    143.         }
    144.     }
    145.  
    146.     public void SendMusic(Text music)
    147.     {
    148.         Debug.Log(music.text);
    149.         SendMsg(music.text);
    150.     }
    151.  
    152. }
    153.  
    I don't achieve my voting system because I need to compare the title send by the client with the list of my server. I intend to use the dictionaries to increment a value for each of the titles sent.

    I know I ask a lot, I apologize.
    Thank you for your reading.
     
  2. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    For multiple clients, hmm.

    Create the server, bind, listen.
    Add the server socket to your read list.
    Use Socket.Select to monitor the read list.
    When a user connects, accept the connection. Add the new socket to the list.
    Repeat Socket.Select monitoring.
    When Select returns, loop through the list and read the data from each client (socket).
    Act on the data
    Message other clients, if applicable.

    - The list is modified when Socket.Select returns; it contains only sockets with data to be read.

    That's the form/design I'm most familiar with.
     
    Pulsar19 and lordofduct like this.
  3. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hello #methos5k,
    thank you for your answer !

    I understand your logic but the one I applied is not good?
    Because I'm doing well with a single client and I saw after research that it was enough to change the number of Acceptclient with a '' while '' to give access to several clients ...
    However, I can not do it. And I wanted especially if you found a problem on the way I did it :-( (if you have the time of course)
    My code may be disgusting to read, but I can answer all your questions without worries.
    (Thank you very much for your help)
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    TcpListener queues up clients as requests come in. When you call AcceptTcpClient it dequeues the client. At this point you can spin off another thread to deal with that client while the listening thread goes back to waiting for the next queued client.

    Like so:
    Code (csharp):
    1.  
    2.     public class ExampleListener
    3.     {
    4.  
    5.         private TcpListener _listener;
    6.  
    7.         public void Initialize(IPAddress address, int port)
    8.         {
    9.             _listener = new TcpListener(address, port);
    10.             _listener.Start();
    11.  
    12.             ThreadPool.QueueUserWorkItem(this.ListenerWorker, null);
    13.         }
    14.  
    15.         public void Stop()
    16.         {
    17.             if(_listener != null)
    18.             {
    19.                 _listener.Stop();
    20.                 _listener = null;
    21.             }
    22.         }
    23.  
    24.         private void ListenerWorker(object token)
    25.         {
    26.             while(_listener != null)
    27.             {
    28.                 var client = _listener.AcceptTcpClient();
    29.                 ThreadPool.QueueUserWorkItem(this.HandleClientWorker, client);
    30.             }
    31.         }
    32.  
    33.         private void HandleClientWorker(object token)
    34.         {
    35.             Byte[] bytes = new Byte[1024];
    36.             StringBuilder builder = new StringBuilder();
    37.  
    38.             using (var client = token as TcpClient)
    39.             using (var stream = client.GetStream())
    40.             {
    41.                 int length;
    42.                
    43.                 while((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    44.                 {
    45.                     builder.Append(Encoding.ASCII.GetString(bytes, 0, length));
    46.                 }
    47.  
    48.                 var msg = builder.ToString();
    49.                 //do something with complete message
    50.             }
    51.         }
    52.  
    53.     }
    54.  
     
    Pulsar19 likes this.
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    I'd also like to point out that StreamReader exists:
    https://msdn.microsoft.com/en-us/library/system.io.streamreader(v=vs.110).aspx

    Code (csharp):
    1.  
    2.         private void HandleClientWorker(object token)
    3.         {
    4.             Byte[] bytes = new Byte[1024];
    5.             string msg;
    6.  
    7.             using (var client = token as TcpClient)
    8.             using (var stream = client.GetStream())
    9.             using (var reader = new StreamReader(stream, Encoding.ASCII))
    10.             {
    11.                 msg = reader.ReadToEnd();
    12.             }
    13.          
    14.             //do something with msg
    15.         }
    16.  
     
    Pulsar19 likes this.
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I think more info would be needed to talk about the threading structure.
    To me, a reasonable number of clients can be handled on 1 thread with no trouble at all.

    Having the main TCP code altogether in its own thread could be good. It's possible to do it in the main thread, in Unity, also.
    To be honest, I'm not really even used to using streams for sockets. :)

    I think it would be easier to try to put something together based on what I said, and/or what @lordofduct said and then come back with some snippets if you get confused.
     
    Last edited: Apr 27, 2018
    Pulsar19 likes this.
  7. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I found some old code, which was not used or fixed up much, but perhaps it can better illustrate my points:
    Code (csharp):
    1.  
    2. connectedUsers = new List<Socket>();
    3. users = new List<User>();
    4. User u;
    5.            
    6. server = new TcpListener(IPAddress.Any,9000);
    7. server.Start();
    8. while (true)
    9. {
    10.    // method that adds the listener and all the current users' sockets to 'connectedUsers'
    11.    AddSockets();
    12.    Socket.Select(connectedUsers, null, null, -1); // wait forever* (-1)
    13.    for(int i = 0; i < connectedUsers.Count; ++i)
    14.    {
    15.        // special case, if it's the listener; we accept a new socket, add the user, etc..
    16.       if(connectedUsers[i] == server.Server)
    17.       {
    18.          Socket s = connectedUsers[i].Accept();
    19.          u = new User
    20.          {
    21.             sock = s,
    22.             name = "New User"
    23.          };
    24.         ColorStr("New user joined");
    25.         users.Add(u);
    26.         continue;
    27.      }
    28.    byte[] buff = new byte[512];
    29.    try
    30.    {
    31.       int len = connectedUsers[i].Receive(buff);
    32.       ColorStr("Len = " + len);
    33.    }
    34.    // for lost connections/disconnects?
    35.    catch (SocketException se)
    36.    {
    37.       DestroyUser(connectedUsers[i]);
    38.       break;
    39.    }
    40.                
    41.    string msg = Encoding.ASCII.GetString(buff);
    42.    u = GetUser(connectedUsers[i]);
    43.    // process message here.
    44.    // I only left these 2 irrelevant methods here, so the code didn't end with a comment ;)
    45.    WriteAll(u, msg);
    46.    ColorStr("Msg: " + msg);
    47.   }
    48. }
    Something like that..
     
    Pulsar19 likes this.
  8. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hello,

    Thank you for your answer @lordofduct and @methos5k !

    I worked on your solutions and finally I preferred to implement the ThreadPool idea.
    So, I have the following code for sending / receiving String on my server :
    (I didn't edit the client because I don't think there is a problem)
    Code (CSharp):
    1.     private void ListenForIncommingRequests()
    2.     {
    3.         tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8052);
    4.         tcpListener.Start();
    5.         ThreadPool.QueueUserWorkItem(this.ListenerWorker, null);
    6.     }
    7.  
    8.     private void ListenerWorker(object token)
    9.     {
    10.         while (tcpListener != null)
    11.         {
    12.             connectedTcpClient = tcpListener.AcceptTcpClient();
    13.             ThreadPool.QueueUserWorkItem(this.HandleClientWorker, connectedTcpClient);
    14.         }
    15.     }
    16.  
    17.     private void HandleClientWorker(object token)
    18.     {
    19.         Byte[] bytes = new Byte[1024];
    20.  
    21.         using (var client = token as TcpClient)
    22.         using (var stream = client.GetStream())
    23.         {
    24.             int length;
    25.             // Read incomming stream into byte arrary.                    
    26.              while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    27.             {
    28.               var incommingData = new byte[length];
    29.               Array.Copy(bytes, 0, incommingData, 0, length);
    30.               // Convert byte array to string message.                        
    31.               string clientMessage = Encoding.ASCII.GetString(incommingData);
    32.               Debug.Log(clientMessage);
    33.               msg = clientMessage;
    34.              }
    35.         }
    36.     }
    37.  
    38.  
    39.     private void SendMessage()
    40.     {
    41.         if (connectedTcpClient == null)
    42.         {
    43.             return;
    44.         }
    45.  
    46.         try
    47.         {
    48.             // Get a stream object for writing.        
    49.             NetworkStream stream = connectedTcpClient.GetStream();
    50.             if (stream.CanWrite)
    51.             {
    52.                 //string serverMessage = "This is a message from your server.";
    53.                 // Convert string message to byte array.            
    54.                 byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(listSongsNames);
    55.                 // Write byte array to socketConnection stream.          
    56.                 stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    57.                 Debug.Log("Server sent his message - should be received by client");
    58.             }
    59.         }
    60.         catch (SocketException socketException)
    61.         {
    62.             Debug.Log("Socket exception: " + socketException);
    63.         }
    64.     }
    In Start (), I call only this method:

    Code (CSharp):
    1. void Start()
    2.     {
    3.         ListenForIncommingRequests();
    4.      }
    and I get this error when I try to connect a second client :
    Socket exception: System.Net.Sockets.SocketException ...
    I think my mistake is stupid and I didn't grab your logic (sorry:oops:) :(
     
    Last edited: May 4, 2018
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    What was the full exception?

    Possibly because you are re-using the same TcpClient variable?
     
    Pulsar19 likes this.
  10. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hey methos,
    The full sentence is : Socket exception: System.Net.Sockets.SocketException ...no connection could be made because the target machine actively refused it 192....

    I found the problem :D (but there is something weird)
    I added these on the start () :

    Code (CSharp):
    1. void Start()
    2.     {
    3. tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests));
    4.         tcpListenerThread.IsBackground = true;
    5.         tcpListenerThread.Start();
    6.         ListenerWorker(token);
    7.     }
    and I switch the ip ''127.0.0.1'' with Ipadress.Any on ListenForIncommingRequest :
    Code (CSharp):
    1.     private void ListenForIncommingRequests()
    2.     {
    3.         tcpListener = new TcpListener(IPAddress.Any, 8052);
    I can connect 5 phones without problem to my pc with wifi and 5 phones can send me messages without problem.
    The funny thing is that I can send a string from the pc for only the last phone that connected.
    So if I connect a phone (at a time), they will each receive the message one by one but if all phones are connected at the same time, the last one who connected will receive the message from the pc.
    I think it's because of my way of handling threads? What do you think ?

    (Thank you !)
     
  11. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Well, glad you sorted out the other issue. lol
    My initially wrong guess is I believe the reason you can only send to the last connected phone. :)

    If you look at @lordofduct 's answer, he created a new TcpClient when accepting the connection. You are only using 1 variable. For multiple clients, you'd probably want to create a list or dictionary, depending on what sounds better for what you're doing.
     
    Pulsar19 likes this.
  12. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Thank you methos!
    I worked on it and got an almost correct result.
    But this result made me notice something important ... :

    When I connect with different phones, I manage to get the list of music on each phone (since I added customers with the list by your answer).
    However, the problem is that once I get my list of music (from PC) on the 5 phones, I can not send or receive a message (string) between the pc and the 5 phones because I have this error :

    ObjectDisposedException: The object was used after being disposed.
    System.Net.Sockets.TcpClient.CheckDisposed ()
    System.Net.Sockets.TcpClient.GetStream ()
    MusicCode.SendMessage (System.Object token) (at Assets / Scripts / MusicCode.cs: 274)
    MusicCode.Update () (at Assets / Scripts / MusicCode.cs: 305)

    Thanks to this error because I realize that if a client disconnects, I would get this same error since the client of the list would not have been there.
    But before having this second future error, I do not find how to solve the one that would send my messages without my objects being deleted as the error says :(

    Here is my code (very simple) that seems perfect (I do not understand where this object removal comes from :confused:):


    Code (CSharp):
    1. private void ListenForIncommingRequests()
    2.     {
    3.         tcpListener = new TcpListener(IPAddress.Any, 8052);
    4.         tcpListener.Start();
    5.        
    6.         ThreadPool.QueueUserWorkItem(this.ListenerWorker, null);
    7.     }
    8.  
    9.  
    10.     private void ListenerWorker(object token)
    11.     {
    12.        
    13.         while (tcpListener != null)
    14.         {
    15.             connectedTcpClient = tcpListener.AcceptTcpClient();
    16.             listConnectedClients.Add(connectedTcpClient);
    17.            // Thread thread = new Thread(HandleClientWorker);
    18.            // thread.Start(connectedTcpClient);
    19.             ThreadPool.QueueUserWorkItem(this.HandleClientWorker, connectedTcpClient);
    20.         }
    21.     }
    22.  
    23.  
    24.  
    25.     private void HandleClientWorker(object token)
    26.     {
    27.         Byte[] bytes = new Byte[1024];
    28.      
    29.         using (var client = token as TcpClient)
    30.         using (var stream = client.GetStream())
    31.         {
    32.             Debug.Log("Nouveau Client connecté");
    33.             int length;
    34.             // Read incomming stream into byte arrary.                        
    35.              while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    36.              {
    37.               var incommingData = new byte[length];
    38.               Array.Copy(bytes, 0, incommingData, 0, length);
    39.               // Convert byte array to string message.                            
    40.               string clientMessage = Encoding.ASCII.GetString(incommingData);
    41.               Debug.Log(clientMessage);
    42.               msg = clientMessage;
    43.              }
    44.             if (connectedTcpClient == null)
    45.             {
    46.                 return;
    47.             }
    48.         }
    49.       //  ThreadPool.QueueUserWorkItem(this.SendMessage, connectedTcpClient);
    50.     }
    51.  
    52.  
    53.  
    54.     private void SendMessage(object token)
    55.     {
    56.        if (connectedTcpClient == null)
    57.        {
    58.             Debug.Log("Problem connectedTCPClient null");
    59.             return;
    60.        }
    61.  
    62.         using (var client = token as TcpClient)              
    63.         using (var stream = client.GetStream()) // Get a stream object for writing.
    64.         {
    65.             if (stream.CanWrite)
    66.             {
    67.                 try
    68.                 {
    69.                     // Convert string message to byte array.                
    70.                     byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(listSongsNames);
    71.                     // Write byte array to socketConnection stream.              
    72.                     stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    73.                     Debug.Log("Server sent his message - should be received by client");
    74.  
    75.                 }
    76.                 catch (SocketException socketException)
    77.                 {
    78.                     Debug.Log("Socket exception: " + socketException);
    79.                 }
    80.             }
    81.         }
    82.      }
    83.  
    84.  
    85.     // Update is called once per frame
    86.     void Update()
    87.     {
    88.  
    89.         if (Input.GetKeyDown(KeyCode.Space))
    90.         {
    91.             foreach (TcpClient item in listConnectedClients)
    92.             {
    93.                 SendMessage(item);
    94.             }
    95.         }
    96.         if (msg != null)
    97.         {
    98.             switch (msg)
    99.             {
    100.                 case "connected":
    101.                     foreach (TcpClient item in listConnectedClients)
    102.                     {
    103.                         SendMessage(item);
    104.                     }
    105.                     msg = null;
    106.                     break;
    107.                 default:
    108.                     if (voteCount.ContainsKey(msg))
    109.                      {
    110.                         voteCount[msg] += 1;
    111.                      }
    112.                     Debug.Log(voteCount);
    113.                     msg = null;
    114.                     break;
    115.             }
    116.         }
    117.  
    118.         foreach (string chemin in fileList)
    119.         {
    120.             var title = Path.GetFileNameWithoutExtension(chemin);
    121.             var item = GameObject.Find(title);
    122.             item.GetComponentInChildren<Text>().text = title + " -    +" + voteCount[title].ToString();
    123.         }
    124.     }
    So ;
    (For now) I know how to connect all my clients (the 5 phones) without worries and I know how to send messages from my phones to the PC indefinitely.
    But as soon as the server sends a single message to clients, nothing more can be sent between client -> server or server -> client.

    What do you think please ? :oops:
     
  13. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hello everyone !

    I have news :
    I noticed where the problem comes from! It is because of my modification of the sendmessage because before its modification, I could send to the same phone, several messages (and to receive as well).
    So I have to limit myself to one phone to avoid this bug ... I'm trapped because I want to send several messages to several phones.

    The old sendmessage() :
    Code (CSharp):
    1. private void SendMessage()
    2.     {
    3.         if (connectedTcpClient == null)
    4.         {
    5.             Debug.Log("Problem connectedTCPClient null");
    6.             return;
    7.         }
    8.  
    9.         try
    10.         {
    11.             // Get a stream object for writing.      
    12.             NetworkStream stream = connectedTcpClient.GetStream();
    13.             if (stream.CanWrite)
    14.             {
    15.                 //string serverMessage = "This is a message from your server.";
    16.                 // Convert string message to byte array.          
    17.                 byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(listSongsNames);
    18.                 // Write byte array to socketConnection stream.        
    19.                 stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    20.                 Debug.Log("Server sent his message - should be received by client");
    21.             }
    22.         }
    23.         catch (SocketException socketException)
    24.         {
    25.             Debug.Log("Socket exception: " + socketException);
    26.         }
    27.     }
    the new sendmessage() :
    Code (CSharp):
    1. private void SendMessage(object token)
    2.      {
    3.          if (connectedTcpClient == null)
    4.          {
    5.              Debug.Log("Problem connectedTCPClient null");
    6.              return;
    7.          }
    8.  
    9.          using (var client = token as TcpClient)
    10.          {
    11.              try
    12.              {
    13.  
    14.                  NetworkStream stream = client.GetStream();
    15.                  if (stream.CanWrite)
    16.                  {
    17.                      // Get a stream object for writing.      
    18.  
    19.                      // Convert string message to byte array.                
    20.                      byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(listSongsNames);
    21.                      // Write byte array to socketConnection stream.              
    22.                      stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    23.                      Debug.Log("Server sent his message - should be received by client");
    24.                  }
    25.              }
    26.              catch (SocketException socketException)
    27.              {
    28.                  Debug.Log("Socket exception: " + socketException);
    29.                  return;
    30.              }
    31.          }
    What do you think ? Someone would have any idea? :)
     
    Nicks2580 likes this.
  14. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Remove the 'using' statements for sending the message. They are disposing of your objects.
    I just tested that & threaded a receive, along with a sleep delayed send.. just 1 client, but after removing those statements from the SendMessage, it was working. :)
     
    Pulsar19 likes this.
  15. Pulsar19

    Pulsar19

    Joined:
    Feb 21, 2018
    Posts:
    15
    Hey @methos5k

    I finally fixed everything + I made a version with asynchronous message that works much better.
    I am very happy, now I understand better my mistakes (beginners) ... thanks to your advice. :)

    Thank you very much for all your answers and see you soon on other topics :rolleyes: !

    [RESOLVED]
     
    Last edited: May 7, 2018
  16. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Nice, glad to hear it. :)
     
    Pulsar19 likes this.
  17. mazedia_willy

    mazedia_willy

    Joined:
    Apr 28, 2017
    Posts:
    1
    @Pulsar19 Well done for your great work.
    Please, could you post your last working version ?
    It would help me a lot.
    Thank U
     
  18. Nicks2580

    Nicks2580

    Joined:
    Mar 21, 2018
    Posts:
    5
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Net;
    5. using System.Net.Sockets;
    6. using System.Text;
    7. using System.Threading;
    8. using UnityEngine;
    9. public class ExampleListener : MonoBehaviour
    10. {
    11.     private List<TcpClient> listConnectedClients = new List<TcpClient>(new TcpClient[0]);
    12.     private TcpListener tcpListener;
    13.     /// <summary>
    14.     /// Background thread for TcpServer workload.  
    15.     /// </summary>  
    16.     private Thread tcpListenerThread;
    17.     /// <summary>  
    18.     /// Create handle to connected tcp client.  
    19.     /// </summary>  
    20.     private TcpClient connectedTcpClient;
    21.     private void ListenForIncommingRequests()
    22.     {
    23.         tcpListener = new TcpListener(IPAddress.Any, 8052);
    24.         tcpListener.Start();
    25.         ThreadPool.QueueUserWorkItem(this.ListenerWorker, null);
    26.     }
    27.     private void ListenerWorker(object token)
    28.     {
    29.         while (tcpListener != null)
    30.         {
    31.             print("Its here");
    32.             connectedTcpClient = tcpListener.AcceptTcpClient();
    33.             listConnectedClients.Add(connectedTcpClient);
    34.             // Thread thread = new Thread(HandleClientWorker);
    35.             // thread.Start(connectedTcpClient);
    36.             ThreadPool.QueueUserWorkItem(this.HandleClientWorker, connectedTcpClient);
    37.         }
    38.     }
    39.     private void HandleClientWorker(object token)
    40.     {
    41.         Byte[] bytes = new Byte[1024];
    42.         using (var client = token as TcpClient)
    43.         using (var stream = client.GetStream())
    44.         {
    45.             Debug.Log("Nouveau Client connecté");
    46.             int length;
    47.             // Read incomming stream into byte arrary.                      
    48.             while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
    49.             {
    50.                 var incommingData = new byte[length];
    51.                 Array.Copy(bytes, 0, incommingData, 0, length);
    52.                 // Convert byte array to string message.                          
    53.                 string clientMessage = Encoding.ASCII.GetString(incommingData);
    54.                 Debug.Log(clientMessage);
    55.                // msg = clientMessage;
    56.             }
    57.             if (connectedTcpClient == null)
    58.             {
    59.                 return;
    60.             }
    61.         }
    62.         //  ThreadPool.QueueUserWorkItem(this.SendMessage, connectedTcpClient);
    63.     }
    64.     private void SendMessage(object token, string msg)
    65.     {
    66.         if (connectedTcpClient == null)
    67.         {
    68.             Debug.Log("Problem connectedTCPClient null");
    69.             return;
    70.         }
    71.         var client = token as TcpClient;
    72.         {
    73.             try
    74.             {
    75.                 NetworkStream stream = client.GetStream();
    76.                 if (stream.CanWrite)
    77.                 {
    78.                     // Get a stream object for writing.    
    79.                     // Convert string message to byte array.              
    80.                     byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(msg);
    81.                     // Write byte array to socketConnection stream.            
    82.                     stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
    83.                     Debug.Log("Server sent his message - should be received by client");
    84.                 }
    85.             }
    86.             catch (SocketException socketException)
    87.             {
    88.                 Debug.Log("Socket exception: " + socketException);
    89.                 return;
    90.             }
    91.         }
    92.     }
    93.         void Start()
    94.     {
    95.         tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests));
    96.         tcpListenerThread.IsBackground = true;
    97.         tcpListenerThread.Start();
    98.      
    99.     }
    100.     // Update is called once per frame
    101.     void Update()
    102.     {
    103.     }
    104.     public void openCamera()
    105.     {
    106.         if (listConnectedClients != null)
    107.         {
    108.             print("Length " + listConnectedClients.Count);
    109.         }
    110.         //SendMessage( "open_camera");
    111.         foreach (TcpClient item in listConnectedClients)
    112.         {
    113.             SendMessage(item, "open_camera");
    114.         }
    115.     }
    116. }
    Full working code for more than one client.