【发布时间】:2018-01-22 04:01:29
【问题描述】:
我正在构建一个客户端/服务器应用程序以了解基于客户端/服务器的游戏如何工作,但该应用程序似乎无法正常运行,这是我的问题:
- 为什么我关闭客户端应用时这个应用不能写“玩家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);
}
}
【问题讨论】:
-
我假设的“C/S”是指“客户端/服务器”?您的问题的某些部分暗示了这一点,但从未明确说明过。
-
你的问题太宽泛了。对最简单部分的简短回答:您无法检查客户端状态,因为您的代码卡在
AcceptTcpClient()调用中。如果您使用调试器查看代码在做什么,您就会看到。解决此类问题的常用方法是编写异步代码,这样您就可以在网络 I/O 事件发生时对其进行响应,而不会阻止任何一个线程响应。我有一个例子,在我最近发布的this answer 中。
标签: c# networking