Правильная инициализация и настройка сокета в TCP-соединении C# - PullRequest
0 голосов
/ 29 мая 2020

У меня вопрос по следующему коду:

    private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private static readonly List<Socket> clientSockets = new List<Socket>();
        private const int BUFFER_SIZE = 1024*2;
        private static readonly byte[] buffer = new byte[BUFFER_SIZE];
        public static Manager Manager { get; set; }
        private static bool firstInit = true;

        /// <summary>
        /// Config and start the server
        /// </summary>
        public static void SetupServer()
        {
            try
            {
                Manager.PCForm.ConnectionButtonStatus(false);
                var PORT = int.Parse(Properties.Settings.Default.LocalPort);
                var listenToAny = Properties.Settings.Default.ListenToAny;
                var IP = GetSocketIP(listenToAny);

                Logger.LogInfo("Setting up server...");

                if(Properties.Settings.Default.UseLocalWifiNetwork)
                {
                    Logger.LogInfo("PC Local IP: " + LocalIPAddress);
                }
                else
                {
                    Logger.LogInfo("PC External IP: " + ExternalIPAddress);
                }           

                if(firstInit)
                {
                    firstInit = false;
                    Logger.LogDebug("Binding new port:" + PORT);
                    serverSocket.Bind(new IPEndPoint(IP, PORT));
                }
                else
                {
                    Logger.LogDebug("Using port that was already binded");
                }

                serverSocket.Listen(0);
                Logger.LogDebug("Listening To: " + IP + ":" + PORT);
                serverSocket.BeginAccept(AcceptCallback, null);
                Manager.PCForm.ConnectionButtonStatus(true);
                Logger.LogInfo("Server setup complete");
            }
            catch(Exception ex)
            {
                FormsHelpers.ShowErrorMessage(ex.Message);
                Logger.LogError("Fail to setup server. Please restart the app.");
            }
        }

   public static void CloseAllSockets()
        {
            try
            {
                Logger.LogDebug("Closing All Sockets...");
                Manager.PCForm.ConnectionButtonStatus(false);
                foreach(Socket socket in clientSockets.ToArray())
                {
                    CloseSocket(socket);
                }

                serverSocket.Close();
                Logger.LogInfo("Server was shutdown");
                Manager.PCForm.ConnectionButtonStatus(true);
            }
            catch(Exception ex)
            {
                Console.WriteLine("Fail to close sockets.\r\nExpection: " + ex.Message);
            }
        }

Моя проблема началась, когда я захотел повторно использовать связанный сокет. Мое приложение поддерживает закрытие и повторное открытие TCP-соединения на сервере (это может быть тот же порт или новый).

Сценарий:

1. Пользователь запускает сервер (открывает сокет TCP на локальном IP-адресе и порту 5000.

2. Пользователь останавливает сервер (сервер закрывает TCP-соединение клиентов и сокет сервера)

3. Пользователь снова запускает сервер (тот же порт - 5000 или новый порт, если пользователь изменил порт в настройках приложения).

Когда пользователь снова запускает сервер с тем же портом (5000), я получаю сообщение об ошибке: Невозможно получить доступ к удаленному объекту! Когда пользователь снова запускает сервер с новым портом (5001), я получаю сообщение об ошибке: недопустимый аргумент (поскольку сокет сервера был привязан к другому порту).

Если я удалю код serverSocket.Close(); он будет работать, потому что только без изменения порта из-за того, что сокет сервера никогда не был закрыт. Посмотрите netstat в этом случае:

enter image description here

Но это плохо, потому что это не позволяет изменить порт, пока конфигурация не будет сохранена и пользователь не перезапустит приложение.

1 Ответ

0 голосов
/ 29 мая 2020

Я обновил код. Когда я выключаю сервер, я отключаю только клиентов. когда я запускаю сервер, я повторно использую последний сокет, но если я изменю порт, я закрою его, выделю новый экземпляр socketServer и использую его.

  if(portInUse.Equals(PORT))
                {
                    Logger.LogDebug("Using port that was already binded");
                }
                else
                {
                    Logger.LogDebug("Binding new port:" + PORT);

                    if(serverSocket != null)
                    {
                        //close previous socket because it was using old port
                        serverSocket.Close();
                    }

                    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    serverSocket.Bind(new IPEndPoint(IP, PORT));
                    portInUse = PORT;
                }
...