C# winform 简单五子棋 200代码实现双人网络匹配对战
接上次的五子棋案例,此次实现的是在局域网中的简单匹配对战,即当一个玩家点击准备对战时,连接服务器并开启一个线程监听服务器反馈回来的消息,然后解析消息,执行对应操作。
服务器匹配思路:
(1)收到玩家1的准备信息,把玩家1加入到准备队列
(2)收到玩家2的准备信息,把玩家2加入到准备队列
(3)当准备队列有两个人时,把这两个ip的玩家合成一个在玩局加入到正在游戏队列,同时从准备队列中移除这两个玩家
(4)当服务器收到玩家信息时去查询正在游戏队列中包含收到玩家信息的ip,把对应消息给这两个ip返回
(5)客户端对服务器返回的消息解析,执行不同的操作
服务器端代码:
客户端实体类Client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
class Client
{
private Socket clientSocket;
private Thread t;
private byte[]data=new byte[1024];
public string ipaddress;
public Client(Socket s,string ipaddress)
{
clientSocket = s;
this.ipaddress = ipaddress;
t=new Thread(ReceiveMessage);
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//在接收数据之前 判断Socket连接是否断开
if (clientSocket.Poll(10,SelectMode.SelectRead))
{
clientSocket.Close();
break;
}
int length=clientSocket.Receive(data);
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine(message);
if (message.Contains("|||Ready|||") && !message.Contains(":"))
{
if (!Program.ReadyClientList.Contains(message.Split('|')[0]))
{
Program.ReadyClientList.Add(message.Split('|')[0]);
}
}
if (Program.GameingClientList.Count > 0)
{
foreach (var temp in Program.GameingClientList)
{
if ((message.Contains(temp.ip1) || message.Contains(temp.ip2) ))
{
foreach (var Temp in Program.clientList)
{
if (Temp.ipaddress == temp.ip1 || Temp.ipaddress == temp.ip2)
{
Temp.SendMessage(message);
}
}
if (message.Equals(temp.ip1 + "|||GameOver|||") || message.Equals(temp.ip2 + "|||GameOver|||"))
{
if (!Program.GameingCancelClientList.Contains(temp))
Program.GameingCancelClientList.Add(temp);
}
}
}
}
if (message.Contains("|||Cancel|||") && !message.Contains(":"))
{
if (!Program.ReadyCancelClientList.Contains(message.Split('|')[0]))
Program.ReadyCancelClientList.Add(message.Split('|')[0]);
}
//清除不在准备游戏列表的对战组别
if (Program.ReadyCancelClientList.Count > 0)
{
foreach (var temp in Program.ReadyCancelClientList)
{
if (Program.ReadyClientList.Contains(temp))
{
Program.ReadyClientList.Remove(temp);
}
}
Program.ReadyCancelClientList.Clear();
}
//清除不在游戏列表的对战组别
if (Program.GameingCancelClientList.Count > 0)
{
foreach (var temp in Program.GameingCancelClientList)
{
if (Program.GameingClientList.Contains(temp))
{
Program.GameingClientList.Remove(temp);
}
}
Program.GameingCancelClientList.Clear();
}
//Console.WriteLine(Program.ReadyClientList.Count);
if (Program.ReadyClientList.Count >= 2)
{
Program.MyStruct myStruct = new Program.MyStruct();
myStruct.ip1 = Program.ReadyClientList[0];
myStruct.ip2 = Program.ReadyClientList[1];
Program.GameingClientList.Add(myStruct);
//Console.WriteLine(myStruct.ip1+" "+myStruct.ip2);
//bool FirstRun = false;
//string FristIp = "";
foreach (var temp in Program.clientList)
{
if (temp.ipaddress == myStruct.ip1)
{
//temp.SendMessage(temp.ipaddress + "||加入房间" + "\n" + "IP为" + temp.ipaddress + "玩家先走!");
//temp.SendMessage("IP为" + temp.ipaddress + "玩家先走!");
//FristIp = temp.ipaddress;
//temp.SendMessage("|||CanDownChess|||");
temp.SendMessage(myStruct.ip2 + "|||CanGame|||" + "|||CanDownChess|||");
//FirstRun = true;
//temp.SendMessage(temp.ipaddress + "加入房间");
// Console.WriteLine(temp.ipaddress);
}
if (temp.ipaddress == myStruct.ip2)
{
//temp.SendMessage(temp.ipaddress + "||加入房间" + "\n" + "IP为" + FristIp + "玩家先走!");
temp.SendMessage(myStruct.ip1 + "|||CanGame|||" );
//temp.SendMessage("IP为" + FristIp + "玩家先走!");
//Console.WriteLine(temp.ipaddress);
}
}
Program.ReadyClientList.Clear();
}
Program.UpdateClientList();
//Console.WriteLine("当前连接人数为:"+Program.clientList.Count);
}
}
public void SendMessage(string s)
{
byte[] _data = Encoding.UTF8.GetBytes(s);
if (clientSocket.Connected)
{
try
{
clientSocket.Send(_data,_data.Length,SocketFlags.None);
}
catch (SocketException)
{
Console.WriteLine("套接字连接异常!");
throw;
}
}
}
public bool Connected
{
get { return clientSocket.Connected; }
}
}
}
主类Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;
namespace Server
{
class Program
{
public struct MyStruct
{
public string ip1;
public string ip2;
}
//所有连接过的客户端
public static List<Client> clientList = new List<Client>();
//所有准备游戏的客户端
public static List<string> ReadyClientList = new List<string>();
public static List<string> ReadyCancelClientList = new List<string>();
//所有正在游戏的客户端组
public static List<MyStruct> GameingClientList = new List<MyStruct>();
public static List<MyStruct> GameingCancelClientList = new List<MyStruct>();
//检查从clientList清除没有连接服务器的客户端
public static void UpdateClientList()
{
var notConnectedList=new List<Client>();
foreach (var client in clientList)
{
if(!client.Connected)
notConnectedList.Add(client);
}
//清除不连接的客户端
foreach (var temp in notConnectedList)
{
clientList.Remove(temp);
}
notConnectedList.Clear();
}
static string ipaddress = "125.217.40.147";
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Parse(ipaddress),7788));
socket.Listen(100);
Console.WriteLine("服务器正在运行......");
while (true)
{
Socket clientSocket = socket.Accept();
Console.WriteLine("IP为"+((IPEndPoint)clientSocket.RemoteEndPoint).Address + "的客户端与服务器进行了连接!");
Client client = new Client(clientSocket, ((IPEndPoint)clientSocket.RemoteEndPoint).Address.ToString());//把每个客户端通信的逻辑放到client类进行处理
client.SendMessage(client.ipaddress + "|||Welcome to the world of Wzq|||");
clientList.Add(client);
}
}
}
}
客户端连接:
private string ipaddress = "125.217.40.147";
private int port = 7788;
public Socket clientSocket;
private Thread t;
private byte[]data=new byte[1024];
private string message = "";
public string IpAddress;
// 线程监听,自己定义,自己在使用时调用
// 解析message并执行操作
void Update (){
}
public void ConnectToServer()
{
clientSocket=new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
//跟服务器进行连接
try
{
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipaddress), port));
}
catch (Exception)
{
// show "很遗憾你没有连接上服务器,请点击准备游戏重新连接!";
throw;
}
//创建一个新的线程用于接收消息
if (clientSocket.Connected)
{
t = new Thread(Receivemessage);
t.Start();
}
}
void Receivemessage()
{
while (true)
{
if (clientSocket.Connected==false)
{
break;
}
int length = clientSocket.Receive(data);
message = Encoding.UTF8.GetString(data, 0, length);
}
}
public void Sendmessage(string s)
{
byte[] data = Encoding.UTF8.GetBytes(s);
clientSocket.Send(data);
}
准备游戏调用:Sendmessage(your IpAddress + "|||Ready|||");
取消准备调用:Sendmessage(your IpAddress+"|||Cancel|||");
下棋时调用:Sendmessage(your IpAddress + "|||CanDownChess|||" + "chess|||" + 棋子x坐标 + "|" + 棋子y坐标);
悔棋时调用:Sendmessage(your IpAddress+"|||Regred|||");
认输或者中途退出游戏时调用:Sendmessage(your IpAddress + "|||Surrender|||");
这样,简单的匹配对战就完成了。当然,解析服务器返回消息并执行操作自己实现。这个只是个简单的思路,实际实现和服务器传递消息要做相应的请求接口,如果要长久保存数据,还要引入数据库的内容。