Как я могу заставить серверную программу работать независимо от того, что происходит с клиентом? - PullRequest
1 голос
/ 28 апреля 2019

Посмотрите на следующие две программы:

//Server

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace MyServerProgram
{
    class Program
    {
        static void Main(string[] args)
        {            
            IPAddress ip = IPAddress.Parse("127.0.0.1");
            int port = 2000;
            TcpListener listener = new TcpListener(ip, port);
            listener.Start();

            TcpClient client = listener.AcceptTcpClient();
            Console.WriteLine("Connected " + ((IPEndPoint)client.Client.RemoteEndPoint).Address);


            NetworkStream netStream = client.GetStream();

            BinaryReader br = new BinaryReader(netStream);

            try
            {
                while (client.Client.Connected)
                {
                    string str = br.ReadString();

                    Console.WriteLine(str);
                }
            }
            catch (Exception ex)
            {
                var inner = ex.InnerException as SocketException;
                if (inner != null && inner.SocketErrorCode == SocketError.ConnectionReset)
                    Console.WriteLine("Disconnected");
                else
                    Console.WriteLine(ex.Message);

                br.Close();
                netStream.Close();
                client.Close();
                listener.Stop();
            }
        }
    }
}


//Client

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace MyClientProgram
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 2000;
            TcpClient client = new TcpClient("localhost", port);

            NetworkStream netStream = client.GetStream();

            BinaryWriter br = new BinaryWriter(netStream);

            try
            {
                int i=1;
                while (client.Client.Connected)
                {
                    br.Write(i.ToString());
                    br.Flush();
                    i++;

                    int milliseconds = 2000;
                    System.Threading.Thread.Sleep(milliseconds);
                }
            }
            catch
            {
                br.Close();
                netStream.Close();
                client.Close();
            }
        }
    }
}

Проблема, с которой я сталкиваюсь с сервером, заключается в том, что программа сервера завершается, как только клиент закрывается.

Iхотите, чтобы серверная программа продолжала работать независимо от того, что клиент делает или происходит с ним.

Как я могу это сделать?

1 Ответ

3 голосов
/ 28 апреля 2019

Попробуйте поместить цикл while вокруг AcceptTcpClient (и связанной логики).Перефразируя код вашего сервера:

boolean keepRunning = true;
while (keepRunning) {
  TcpClient client = listener.AcceptTcpClient();
  Console.WriteLine("Connected ...") // and other stuff deleted.

  // while client connected...
      string str = br.ReadString();
      // check to see if we should continue running.
      keepRunning = ! "quit".equalsIgnoreCase(str);
  // Other stuff

Обратите внимание, что это очень небезопасно - любой клиент, независимо от того, где / кем он может завершить работу вашего сервера, отправляет сообщение «выход» на ваш сервер.В реальной жизни вам, вероятно, потребуется более строгий механизм.Очевидно, что с этим механизмом вам потребуется, чтобы ваш клиент мог генерировать текст сообщения «выход», когда вам это необходимо.

Другой способ - запустить весь сервер в потоке.Затем в другом потоке найдите метод, который оператор мог бы использовать для закрытия сервера (например, выбор меню в приложении Swing).

Существует множество опций, которые вы можете выбрать для «управления» выключением.

Кроме того, как написано, ваш код является однопоточным.Таким образом, он будет ожидать подключения клиента, иметь дело с этим клиентом и затем завершать работу (или если вы применяете keepRunning во время модификации цикла, ожидайте подключения следующего клиента).Но только один клиент может подключиться к этому серверу одновременно.

Чтобы сделать его многопоточным (может обслуживать несколько клиентов одновременно), поместите тело вашего сервера (код службы) вПоток и вызов нового экземпляра потока для обслуживания этого клиента.После запуска служебного потока основной цикл просто ожидает подключения следующего клиента.Таким образом, ваш основной цикл станет примерно таким:

while (keepRunning) {
    TcpClient client = listener.AcceptTcpClient();
    Console.WriteLine("Connected ...") // and other stuff deleted.

    ServiceThread st = new ServiceThread(client);
    st.start ();
}

, а служебный поток будет выглядеть примерно так:

public class ServiceThread extends Thread {
  private TcpClient client;
  public ServiceThread (TcpClient client) {
    this.client = client;
  }
  @override
  public void run() {
    NetworkStream netStream = client.GetStream();
    BinaryReader br = new BinaryReader(netStream);
    try {
            while (client.Client.Connected) {
            // Stuff deleted for clarity
            }
         }
        catch (Exception ex) {
            // Exception handling stuff deleted for clarity.
        }
  }
}
...