Search code examples
c#tcpclienttcpserver

Tcp client send command toTcp Server to start x.exe and later server ignores client


I have created server and client everything worked just fine until I made 1 change. Created command start x.exe.

 if(flag = Textmessage.ToLower() == "x.exe") //command from client
         {          
            ProcessStartInfo _processStartInfo = new ProcessStartInfo();
            _processStartInfo.WorkingDirectory = @"C:\Users\audrius\OneDrive\Programavimas\x\Bin\Debug\";
            _processStartInfo.FileName = @"x.exe";
            Process myProcess = Process.Start(_processStartInfo);

            byte[] bytes = Encoding.ASCII.GetBytes("exe started");
            socket.Send(bytes);//TELL client program started
            ServerLogs.ServerLog("exe started");
            Console.WriteLine("exe started");
            return;
        }

Everything works fine, I get response from server that program started. BUT then I want to send next command server don't accept it. Only then I restart client, server accept commands again. Why server freezes with this client? My Client code:

 namespace Multi_Client
{
class Program
{
    private static readonly Socket _clientSocket = new Socket
        (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    private const int _PORT = 100;
    static string name = "Client";
    static void Main()
    {
        Console.WriteLine("Welcome {0}", name); 
        Console.Title = "Client";
        ConnectToServer();
        RequestLoop();
        Exit();
    }

    private static void ConnectToServer()
    {
        int attempts = 0;

        while (!_clientSocket.Connected)
        {
            try
            {
                attempts++;
                Console.WriteLine("Connection attempt " + attempts);
                _clientSocket.Connect(IPAddress.Loopback, _PORT);
            }
            catch (SocketException) 
            {
                Console.SetCursorPosition(0, Console.CursorTop - 1);
                Console.Write(new string(' ', Console.WindowWidth));
                Console.SetCursorPosition(0, Console.CursorTop - 1);
            }
        }

       // Console.Clear();
        Console.WriteLine("Connected");
    }

    private static void RequestLoop()
    {
        Console.WriteLine(@"<Type ""exit"" to properly disconnect client>");

        while (true)
        {
            SendRequest();
            ReceiveResponse();
        }
    }

    /// <summary>
    /// Close socket and exit app
    /// </summary>
    private static void Exit()
    {
        SendString(name+ "exit"); // Tell the server we re exiting
        _clientSocket.Shutdown(SocketShutdown.Both);
        _clientSocket.Close();
        System.Threading.Thread.Sleep(1000);
        Environment.Exit(0);
    }

    private static void SendRequest()
    {
        Console.Write("Send a request: ");
        string request = name + " "+ Console.ReadLine();
        SendString(request);
        System.Threading.Thread.Sleep(1000);          

        if (request.ToLower() == name +" exit")
        {
            Exit();
        }
    }
    /// <summary>
    /// Sends a string to the server with ASCII encoding
    /// </summary>
    private static void SendString(string text)
    {
        byte[] buffer = Encoding.ASCII.GetBytes(text);
       _clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);                     
    }

    private static void ReceiveResponse()
    {
        if (_clientSocket.Connected)
        {
            var buffer = new byte[2048];
            int received = _clientSocket.Receive(buffer, SocketFlags.None);
            if (received == 0) return;
            var data = new byte[received];
            Array.Copy(buffer, data, received);
            string text = Encoding.ASCII.GetString(data);
            Console.WriteLine(text);
        }
    }
}

} MY Server:

     namespace Multi_Server
 {
   internal class Program
    {
    private static Socket _serverSocket;
    private static readonly List<Socket> _clientSockets = new List<Socket>      ();
    private const int _BUFFER_SIZE = 2048;
    private const int _PORT = 100;
    private static readonly byte[] _buffer = new byte[1024];

    private static void Main()
    {
        Console.Title = "Server";
        Program.SetupServer();
        Console.ReadLine();
        Program.CloseAllSockets();
    }

    private static void SetupServer()
    {
        ServerLogs.ServerLog("Setting up server...");
        Console.WriteLine("Setting up server...");
        Program._serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Program._serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
        Program._serverSocket.Listen(5);
        Program._serverSocket.BeginAccept(new AsyncCallback(Program.AcceptCallback), null);
        Console.WriteLine("Server setup complete");
        ServerLogs.ServerLog("Server setup complete");
    }

    private static void CloseAllSockets()
    {
        foreach (Socket socket in _clientSockets)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }

        _serverSocket.Close();
    }

    private static void AcceptCallback(IAsyncResult AR)
    {
        Socket socket;
        try
        {
            socket = _serverSocket.EndAccept(AR);
        }
        catch (ObjectDisposedException)
        {
            return;
        }
        Program._clientSockets.Add(socket);
        socket.BeginReceive(Program._buffer, 0, 1024, SocketFlags.None, new AsyncCallback(Program.ReceiveCallback), socket);
        Console.WriteLine("Client connected, waiting for request...");
        ServerLogs.ServerLog("Client connected, waiting for request...");
        _serverSocket.BeginAccept(AcceptCallback, null);
    }

    private static void ReceiveCallback(IAsyncResult AR)
    {
        Socket socket = (Socket)AR.AsyncState;
        int num;
        try
        {
            num = socket.EndReceive(AR);
        }
        catch (SocketException)
        {
            Console.WriteLine("Client forcefully disconnected");
            ServerLogs.ServerLog("Client forcefully disconnected");
            socket.Close();
            _clientSockets.Remove(socket);
            return;
        }
        byte[] array = new byte[num];
        Array.Copy(_buffer, array, num);
        string RawText = Encoding.ASCII.GetString(array);
        char[] textarray = RawText.ToCharArray();
        int i = 0;
        string name = "";

        while (textarray[i] != ' ')
        {
            name += textarray[i];
            i++;
        }
        string Textmessage = RawText.Substring(++i);

        ServerLogs.ServerLog("Received from " + name + " !> Text: " + Textmessage);
        Console.WriteLine("Received from {0} !> Text: {1}", name, Textmessage);

        bool flag;
        if(flag = Textmessage.ToLower() == "get time")
        {
            Console.WriteLine("Text is a get time request");
            ServerLogs.ServerLog("Text is a get time request");
            byte[] bytes = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
            socket.Send(bytes);
            ServerLogs.ServerLog("Time sent to client");
            Console.WriteLine("Time sent to client");
        }              
        else if(flag = Textmessage.ToLower() == "exit")
        {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                _clientSockets.Remove(socket);
                ServerLogs.ServerLog("Client disconnected");
                Console.WriteLine("Client disconnected");
            return;
        }               
        else if(flag = Textmessage.ToLower() == "x.exe") //command from client
         {             

            ProcessStartInfo _processStartInfo = new ProcessStartInfo();
            _processStartInfo.WorkingDirectory = @"C:\Users\audrius\OneDrive\Programavimas C#\Steambot Scrapper\Bin\Debug\";
            _processStartInfo.FileName = @"x.exe";
            Process myProcess = Process.Start(_processStartInfo);

            byte[] bytes = Encoding.ASCII.GetBytes("exe started");
            socket.Send(bytes);
            ServerLogs.ServerLog("exe started");
            Console.WriteLine("exe started");
            return;
        }
        else 
         { 
            ServerLogs.ServerLog("Text is an invalid request");
            Console.WriteLine("Text is an invalid request");
            byte[] bytes = Encoding.ASCII.GetBytes("Invalid request");
            socket.Send(bytes);
            ServerLogs.ServerLog("Warning Sent");
            Console.WriteLine("Warning Sent");
         }
        socket.BeginReceive(_buffer, 0, 1024, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
    }
}
  }//ServerLogs.cs >>>
   class ServerLogs
   {
    private static string m_exePath = string.Empty;
    public  ServerLogs(string logMessage)
    {
        ServerLog(logMessage);
    }

    public static void ServerLog(string logMessage)
    {
        m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        try
        {
            using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
            {
                Log(logMessage, w);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: "+ex);
        }
    }

    public static void Log(string logMessage, TextWriter txtWriter)
    {
        try
        {
            txtWriter.Write("\nLog Entry: ");
            txtWriter.WriteLine("{0} {1} : {2}", 
                DateTime.Now.DayOfWeek, DateTime.Now.ToLongTimeString(), logMessage);
          //  txtWriter.WriteLine("  :");
         //   txtWriter.Write(" :{0}", logMessage);
          //  txtWriter.WriteLine("-------------------------------");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex);
        }
    }


}

Solution

  • First of all (for future use), you are way better of using the TcpClient and TcpListener classes instead, they make things much easier.

    Secondly, I see no meaning in the flag boolean. It's completely useless. If you need to check something just do if(Textmessage.ToLower() == "x.exe") as it already returns a bool.

    Thirdly and finally, your server stops receiving due to that you don't make it start waiting for data again after a command has been processed. After you've processed a valid command you call return; which will stop your code from calling the socket.BeginReceive() method.

    else if(flag = Textmessage.ToLower() == "x.exe") //command from client
    {          
       ...code...
       return; //<-- Your problem.
    }
    

    You should remove every return; that you have in your ReceiveCallback method, EXCEPT for the one in the block where you disconnect, since the others are useless. Once an if or else if block successfully executes the other ones will be ignored - meaning that you do not have to terminate the method.

    Removing the returns will make your

    socket.BeginReceive(_buffer, 0, 1024, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
    

    line always execute, thus meaning that the server will keep reading commands until the connection is terminated.