1

I am building a Client/Server Application to learn how Game based on Client/Server works, but the application seems can't work well, here are my questions:

  1. Why can't this app can't write "Player XXX leaves" when I close the client application
  2. How to receive data from Server correctly? (I want to receive a position info from Server to render it in Client)

here is the full code:

Server:

public class ServerApp
{
    public class Point
    {
        public int x;
        public int y;
    }

    TcpListener listener;
    List<Player> players;

    string[,] data = new string[20, 40];

    public ServerApp()
    {
        players = new List<Player>();
    }

    void PlayerJoin(TcpClient client)
    {
        lock (data)
        {
            if (data[0, 0] == "*")
            {
                data[0, 0] = "O";
                Player player = new Player();
                player.Entity = "O";
                player.Location = new Vector2(0,0);
                player.Client = client;
                players.Add(player);
            }
            else if (data[0, 39] == "*")
            {
                data[0, 40] = "P";
                Player player = new Player();
                player.Entity = "P";
                player.Location = new Vector2(0, 0);
                player.Client = client;
                players.Add(player);
            }
            else if (data[19, 0] == "*")
            {
                data[20, 0] = "I";
                Player player = new Player();
                player.Entity = "I";
                player.Location = new Vector2(0, 0);
                player.Client = client;
                players.Add(player);
            }
            else if (data[19, 39] == "*")
            {
                data[20, 40] = "U";
                Player player = new Player();
                player.Entity = "U";
                player.Location = new Vector2(0, 0);
                player.Client = client;
                players.Add(player);
            }
        }
    }

    void InitData(ref string[,] data)
    {
        for (int i = 0; i < 20; i++)
        {
            for (int j = 0; j < 40; j++)
            {
                if (i != 0 && i != 19)
                {
                    if (j != 0 && j != 39)
                    {
                        data[i, j] = " ";
                    }
                    else
                    {
                        data[i, j] = "*";
                    }
                }
                else
                {
                    data[i, j] = "*";
                }
            }
        }
    }

    void InitServer()
    {
        listener = new TcpListener(new IPAddress(new byte[] { 127, 0, 0, 1 }), 6666);
        listener.Start();
    }

    void SyncDataToAllClient()
    {
        foreach (var player in players)
        {
            StreamWriter sw = new StreamWriter(player.Client.GetStream());
            int[] pos = new int[2];
            pos[0] = player.Location.x;
            pos[1] = player.Location.y;
            sw.Write(pos[0]);
            sw.Write(pos[1]);
            sw.Close();
        }
    }

    public void Run()
    {
        InitServer();
        InitData(ref data);

        while (true)
        {
            if(listener.pending())
            {
            var myclient = listener.AcceptTcpClient();
            if (myclient != null)
            {
                Console.WriteLine(string.Format("Client from {0} connected!", ((IPEndPoint)myclient.Client.RemoteEndPoint).Address));
                PlayerJoin(myclient);

                Thread.Sleep(1000 * 5);

                StreamWriter sw = new StreamWriter(myclient.GetStream());
                sw.Write(data);
            }
            CheckClient();
            SyncDataToAllClient();
            }
        }
    }

    private void CheckClient()
    {
        foreach (var p in players)
        {
            if (!p.Client.Connected)
            {
                Console.WriteLine("Player {0} leave!", ((IPEndPoint)p.Client.Client.RemoteEndPoint).Address);
                players.Remove(p);
                data[p.Location.y, p.Location.x] = "*";
            }
        }
    }
}

Client:

public class ClientApp
{
    TcpClient client;

    string[,] data = new string[20, 40];
    bool quit;
    public void Run()
    {
        EstablishConntionToServer();
        InitData(ref data);
        while (!quit)
        {
            SyncDataFromServer(ref data);
            PrintData(data);
        }
    }

    void EstablishConntionToServer()
    {
        client = new TcpClient();
        client.Connect(new IPAddress(new byte[] { 127, 0, 0, 1 }), 6666);
    }

    void SyncDataFromServer(ref string[,] data)
    {
        Stream s = client.GetStream();
        char[] buffer=new char[1];
        StreamReader sr = new StreamReader(s);
        sr.Read(buffer,0,1);
    }

    void InitData(ref string[,] data)
    {
        for (int i = 0; i < 20; i++)
        {
            for (int j = 0; j < 40; j++)
            {
                //data[i, j] = "*";
                if (i != 0 && i != 19)
                {
                    if (j != 0 && j != 39)
                    {
                        data[i, j] = " ";
                    }
                    else
                    {
                        data[i, j] = "*";
                    }
                }
                else
                {
                    data[i, j] = "*";
                }
            }
        }
    }

    void PrintData(string[,] data)
    {
        Console.Clear();
        for (int i = 0; i < 20; i++)
        {
            for (int j = 0; j < 40; j++)
            {
                Console.Write(data[i, j]);
            }
            Console.Write(Environment.NewLine);
        }

        System.Threading.Thread.Sleep(500);
    }
}
  • I *assume* by "C/S" you mean "Client/Server"? It's heavily implied by parts of your question but never explicitly spelled out. – Damien_The_Unbeliever Aug 14 '17 at 10:35
  • 1
    Your question is way too broad. The short answer to the simplest part: you can't check the client status, because your code is stuck at the `AcceptTcpClient()` call. Which you'd have seen, if you'd used a debugger to see what the code is doing. The usual way to solve problems like this is to write asynchronous code, so that you can respond to network I/O events as they happen, without preventing any one thread from responding. I have an example of this, in [this answer](https://stackoverflow.com/a/44942011) which I posted recently. – Peter Duniho Aug 14 '17 at 18:28

1 Answers1

0

Solutions:

For transmitting client movements with the server, you would want to use UDP for its speed. It is the most efficient way to transmit data often which is required in games.

As for your other question, it most likely does not know the client left, it is possible your connection never was properly closed and therefore the connection must time out to be recognized as closed.

Sean Mitchell
  • 447
  • 2
  • 21