TCP Server/Client Socket.Connected gibt immer true

  • C#

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Bluespide.

    TCP Server/Client Socket.Connected gibt immer true

    Hallo,

    ich habe mir einen TCP Server und Client gebaut und es funktioniert sehr gut und auch total stabil es fehlt wirklich nur mehr
    ein kleiner Schritt und dann ist alles in Ordnung :)

    Wenn sich ein Client mit meinem Server verbindet, dann wird der Client in eine List of <ClientData>gesteckt aber dort bleibt er für immer drin
    auch wenn der client disconnected.

    Ich gehe mit einem Timer jede Sekunde durch die Liste und Frag mit

    C#-Quellcode

    1. ClientData.clientSocket.Connected
    ab ob der Client noch da ist aber obwohl
    die Client-Anwendung nicht mehr läuft bekomm ich true zurück.


    Server:

    C#-Quellcode

    1. static void ListenThread()
    2. {
    3. for (;;)
    4. {
    5. listenerSocket.Listen(0);
    6. _clients.Add(new ClientData(listenerSocket.Accept()));
    7. }
    8. }
    9. public static void Data_IN(object cSocket)
    10. {
    11. Socket clientSocket = (Socket)cSocket;
    12. byte[] Buffer;
    13. int readBytes;
    14. for (;;)
    15. {
    16. try
    17. {
    18. Buffer = new byte[clientSocket.SendBufferSize];
    19. readBytes = clientSocket.Receive(Buffer);
    20. if (readBytes > 0)
    21. {
    22. Packet packet = new Packet(Buffer);
    23. DataManager(packet);
    24. }
    25. }
    26. catch (SocketException e)
    27. {
    28. MessageBox.Show("A client dced");
    29. }
    30. }
    31. }


    C#-Quellcode

    1. Interessante Stellen von der ClientData Klasse
    2. class ClientData
    3. {
    4. public Socket clientSocket;
    5. public Thread clientThread;
    6. public string temporaryIdentifier;
    7. public string clientIdentifier;
    8. public ClientData()
    9. {
    10. this.temporaryIdentifier = Guid.NewGuid().ToString();
    11. clientThread = new Thread(ServerForm.Data_IN);
    12. clientThread.Start(this.clientSocket);
    13. SendRegistrationPacket();
    14. }
    15. public ClientData(Socket clientSocket)
    16. {
    17. this.clientSocket = clientSocket;
    18. this.temporaryIdentifier = Guid.NewGuid().ToString();
    19. clientThread = new Thread(ServerForm.Data_IN);
    20. clientThread.Start(this.clientSocket);
    21. SendRegistrationPacket();
    22. }
    23. }





    Client:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. using System.Windows.Forms;
    10. using ServerData;
    11. using System.Net;
    12. using System.Net.Sockets;
    13. using System.IO;
    14. using System.Threading;
    15. using Microsoft.Win32;
    16. namespace Client
    17. {
    18. public partial class ClientForm : Form
    19. {
    20. public static Socket master;
    21. public static string temporaryIdentifier;
    22. public static string clientIdentifier;
    23. public ClientForm()
    24. {
    25. InitializeComponent();
    26. clientIdentifier = GetUniqueIdentifierFromRegistry();
    27. }
    28. private void button1_Click(object sender, EventArgs e)
    29. {
    30. string ip = textBox1.Text;
    31. master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    32. IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ip), 4242);
    33. try
    34. {
    35. master.Connect(ipe);
    36. Thread t = new Thread(Data_IN);
    37. t.Start();
    38. } catch
    39. {
    40. MessageBox.Show("Verbindung zum Server fehlgeschlagen.");
    41. Application.Exit();
    42. }
    43. }
    44. static void Data_IN()
    45. {
    46. byte[] Buffer;
    47. int readBytes;
    48. while (master.Connected)
    49. {
    50. try
    51. {
    52. Buffer = new byte[master.SendBufferSize];
    53. readBytes = master.Receive(Buffer);
    54. if (readBytes > 0)
    55. {
    56. DataManager(new Packet(Buffer));
    57. }
    58. } catch(SocketException e)
    59. {
    60. MessageBox.Show("Verbindung zum Server getrennt");
    61. Application.Exit();
    62. }
    63. }
    64. }
    65. static void DataManager(Packet p)
    66. {
    67. switch (p.packetType)
    68. {
    69. case (PacketType.Registration):
    70. temporaryIdentifier = p.Gdata[0];
    71. p.senderID = temporaryIdentifier;
    72. p.Gdata.RemoveAt(0);
    73. p.Gdata.Add(clientIdentifier);
    74. master.Send(p.ToBytes());
    75. break;
    76. case (PacketType.RegistrationSuccess):
    77. p.senderID = temporaryIdentifier;
    78. master.Send(p.ToBytes());
    79. break;
    80. case (PacketType.RegistrationFailed):
    81. MessageBox.Show(p.Gdata[0].ToString());
    82. Application.Exit();
    83. break;
    84. }
    85. }
    86. private string GetUniqueIdentifierFromRegistry()
    87. {
    88. return "GEHEIMEID";
    89. }
    90. private void ClientForm_FormClosing(object sender, FormClosingEventArgs e)
    91. {
    92. master.Disconnect(false);
    93. master.Close();
    94. }
    95. }
    96. }

    msdn schrieb:

    Connected Gets a value that indicates whether a Socket is connected to a remote host as of the last Send or Receive operation.

    msdn.microsoft.com/en-us/libra….connected(v=vs.110).aspx
    Dies bedeutet, das anhand der letzten Operation festgelegt wird, ob der Socket aktiv ist.

    Lösung:
    Sende, bevor der Client schließt, eine Nachricht an den Server, sodass dieser ebenfalls den Socket schließen kann. Damit sparst du dir auch das Polling der Property.
    Bau dir in deiner Client Klasse des Servers eine DateTime Property, die den Zeitpunkt der letzten Aktion (Senden/Empfangen) beherbergt.
    Nun baust du dir nen System.Timers.Timer der alle X Minuten über die Liste Iteriert. Hat eine Verbindung länger als Y Minuten nichts mehr Gesendet oder Empfangen, wird sie gelöscht.
    Dafür hatte ich mir auch mal eine Extension geschrieben

    C#-Quellcode

    1. ​public static bool IsConnected(this TcpClient client) {
    2. try {
    3. return !(client.Client.Poll(0, SelectMode.SelectRead) && client.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
    4. } catch { return false; }
    5. }