如何正确构建客户端/服务器应用程序?
问题描述:
我建立一个客户机/服务器应用程序来学习如何游戏基于客户机/服务器的作品,但应用程序似乎不能很好地工作,这里是我的问题:如何正确构建客户端/服务器应用程序?
- 为什么不能这样应用程序可以” t关闭客户端应用程序时写入“播放器XXX离开”
- 如何正确接收来自服务器的数据? (我想接收来自服务器的位置信息,以使其在客户端)
这里是全码:
服务器:
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] = "*";
}
}
}
}
客户:
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);
}
}
答
解决方案:
对于传输客户端运动w ith服务器,你会想要使用UDP的速度。这是经常在游戏中传输数据的最有效方式。
至于你的其他问题,它最有可能不知道客户端,可能你的连接没有被正确关闭,因此连接必须超时才能被识别为关闭。
我*假设你的意思是“客户/服务器”的“C/S”?这部分问题严重隐含,但从未明确阐述。 –
你的问题太广泛了。对最简单部分的简短回答:您无法检查客户端状态,因为您的代码卡在'AcceptTcpClient()'调用中。你会看到,如果你使用调试器来看看代码在做什么。解决这类问题的常用方法是编写异步代码,以便在网络I/O事件发生时响应,而不会阻止任何一个线程响应。我在最近发布的[这个答案](https://*.com/a/44942011)中有一个例子。 –