最近时间有点忙,本来象棋游戏是有一个网络版本的,但是由于最近时间比较忙,一直没发出来.

最近有一些朋友希望看到网络版象棋,本来这个是学生将做的项目,这里我把这个DEMO给大家,相互学习.


网络象棋,不得不说一下TCP/IP协议,这其实是两个协议,即tcp协议和ip协议。

所谓IP协议,IP协议是在网络层的协议.它主要完成数据包的发送作用。

所谓TCP协议,TCP协议也是建立在IP协议之上的,不过TCP协议是可靠的.按照顺序发送的。

所以正是由于他们的特性,使得他们一起可以使我们网络数据传输可靠。一般我们常说的TCP/IP“三次握手”,其实也就是第一步客户机向服务器发送一个TCP数据包,表示请求建立连接,第二步服务器接收到请求数据包以后再向客户端发送一次响应数据包,第三步客户机接收到以后再想服务器发送一次确认数据包。服务器接受到以后,我们的连接也就成功。


那么socket(套接字)呢?其实也就是两台机器的远程节点,它的操作也包括,打开,关闭,读写等等。

具体的呢,大家可以去看一下关于TCP/IP的书,这里我就不予累赘。


这里呢,本来最早是用了一套我封装好的socket库来做连接和数据传输,后来由于一些原因要把把项目难度减小,所以就用了.net标准的TcpListener和TcpClient来做连接。


这里呢主要是采用原来单机版象棋进行功能扩展的,其实所谓网络版本,也就是将原本在电脑的输入操作换做网络数据输入,所以其他算法和设计都基本一样。这里我讲一下具体实现的网络部分

首先需要创建网络服务器和客户机的登陆部分

中国象棋(网络版) 转载_数据传输

分为服务器和客户机登陆以后:

客户端:

中国象棋(网络版) 转载_服务器_02                TcpClient client = new TcpClient();

中国象棋(网络版) 转载_服务器_02                IPAddress ip = IPAddress.Parse(this.tbIP.Text);

中国象棋(网络版) 转载_服务器_02                int port = Convert.ToInt32( tbPort.Text);

中国象棋(网络版) 转载_服务器_02                client.Connect(ip,port);

中国象棋(网络版) 转载_服务器_02                Flag.PlayerType = Enums.ChessType.red;

中国象棋(网络版) 转载_服务器_02                TcpTransfer tranfer = new TcpTransfer(client);


服务器则是需要建立监听:

中国象棋(网络版) 转载_服务器_02int port = Convert.ToInt32( tbPort.Text);

中国象棋(网络版) 转载_服务器_02                TcpListener listener = new TcpListener(port);

中国象棋(网络版) 转载_服务器_02                listener.Start();

中国象棋(网络版) 转载_服务器_02                TcpClient client = listener.AcceptTcpClient();

中国象棋(网络版) 转载_服务器_02                Flag.PlayerType = Enums.ChessType.blue;

中国象棋(网络版) 转载_服务器_02                TcpTransfer tranfer = new TcpTransfer(client);

中国象棋(网络版) 转载_服务器_02


这里数据传输呢,封装在TcpTransfer类中


中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16/**//// <summary>

中国象棋(网络版) 转载_网络流_17    /// tcp传输控制类

中国象棋(网络版) 转载_子线程_18    /// </summary>

中国象棋(网络版) 转载_服务器_02    public class TcpTransfer 

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16    中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 接收信息事件的委托

中国象棋(网络版) 转载_子线程_26        /// </summary>

中国象棋(网络版) 转载_网络流_17        public delegate void ReceiveMsgHandle(string msg); 

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 接收信息事件

中国象棋(网络版) 转载_子线程_26        /// </summary>

中国象棋(网络版) 转载_网络流_17        public event ReceiveMsgHandle ReceiveMsg;

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 接收信息事件激活方法

中国象棋(网络版) 转载_网络流_17        /// </summary>

中国象棋(网络版) 转载_子线程_26        /// <param name="msg"></param>

中国象棋(网络版) 转载_网络流_17        private void OnReceive(string msg)

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17            if(ReceiveMsg !=null)

中国象棋(网络版) 转载_网络流_17                ReceiveMsg(msg);

中国象棋(网络版) 转载_子线程_26        }

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_17        private TcpClient _client;

中国象棋(网络版) 转载_网络流_17        public TcpTransfer(TcpClient client)

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17            _client = client;

中国象棋(网络版) 转载_子线程_26        }

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 发送信息

中国象棋(网络版) 转载_网络流_17        /// </summary>

中国象棋(网络版) 转载_子线程_26        /// <param name="msg"></param>

中国象棋(网络版) 转载_网络流_17        public void Send(string msg)

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17            //获取网络流

中国象棋(网络版) 转载_网络流_17            NetworkStream ns = _client.GetStream();

中国象棋(网络版) 转载_网络流_17            //将要发送的字符串转换为字节数组

中国象棋(网络版) 转载_网络流_17            byte [] bytes = System.Text.Encoding.Default.GetBytes( msg );

中国象棋(网络版) 转载_网络流_17            //写入网络流

中国象棋(网络版) 转载_网络流_17            ns.Write( bytes,0,bytes.Length );

中国象棋(网络版) 转载_网络流_17            ns.Flush();

中国象棋(网络版) 转载_子线程_26        }

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 接收信息

中国象棋(网络版) 转载_子线程_26        /// </summary>

中国象棋(网络版) 转载_网络流_17        public void Receive()

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24        中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17            //获取网络流

中国象棋(网络版) 转载_网络流_17            NetworkStream ns = _client.GetStream();

中国象棋(网络版) 转载_网络流_17            while(true)

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24            中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17                byte [] bytes = new byte[512];

中国象棋(网络版) 转载_网络流_17                int size = 0;

中国象棋(网络版) 转载_网络流_17                

中国象棋(网络版) 转载_网络流_17                try

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24                中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17                    //刷新流

中国象棋(网络版) 转载_网络流_17                    ns.Flush();

中国象棋(网络版) 转载_网络流_17                    //从网络流里读取信息到byte[]

中国象棋(网络版) 转载_网络流_17                    size = ns.Read(bytes,0,bytes.Length);

中国象棋(网络版) 转载_子线程_26                }

中国象棋(网络版) 转载_网络流_17                catch

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24                中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17                    System.Windows.Forms.MessageBox.Show("tcp连接出现故障!程序异常的退出!");

中国象棋(网络版) 转载_网络流_17                    System.Windows.Forms.Application.Exit();

中国象棋(网络版) 转载_子线程_26                }

中国象棋(网络版) 转载_网络流_17                

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24                /**//*

中国象棋(网络版) 转载_网络流_17                 * 由于socket连接后作为网络传输的会有很多异常

中国象棋(网络版) 转载_网络流_17                 * 在这里我们只是简单的做了一点处理,当然,在实际开发中socket异常的处理绝不仅仅如此简单

中国象棋(网络版) 转载_网络流_17                 * 如果断开连接,有可能会出现一直接收0个字节问题

中国象棋(网络版) 转载_网络流_17                 * 如果接收到0个字节,则退出循环

中国象棋(网络版) 转载_子线程_26                 * */

中国象棋(网络版) 转载_网络流_17                if(size<=0) break;

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_17                //将接收到的字节转换为字符串

中国象棋(网络版) 转载_网络流_17                string msg = System.Text.Encoding.Default.GetString(bytes);

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_17                OnReceive( msg );

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_网络流_17                //当前线程休眠100毫秒

中国象棋(网络版) 转载_网络流_17                System.Threading.Thread.Sleep(100);

中国象棋(网络版) 转载_网络流_17

中国象棋(网络版) 转载_子线程_26            }

中国象棋(网络版) 转载_子线程_26        }

中国象棋(网络版) 转载_子线程_18    }


这里呢,大家注意一下,由于我们的象棋作用是在子线程上,而窗体呢是在主线程上,如果我们用子线程去改变主线程的窗体,则会带来异常或者线程的阻塞。于是,定义了三个委托来处理窗体改变(棋子位置变换问题)问题。

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16/**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 选中操作的异步委托

中国象棋(网络版) 转载_子线程_18        /// </summary>

中国象棋(网络版) 转载_服务器_02        private delegate bool CheckHandle(IChessItem ic);

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 移动操作的异步委托

中国象棋(网络版) 转载_子线程_18        /// </summary>

中国象棋(网络版) 转载_服务器_02        private delegate bool MoveToHandle(int x,int y);

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// 吃棋子的异步委托

中国象棋(网络版) 转载_子线程_18        /// </summary>

中国象棋(网络版) 转载_服务器_02        private delegate bool EatHandle(IChessItem ic);

在我们TCP事件里面,则采用invoke异步的模式进行委托

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16        /**//// <summary>

中国象棋(网络版) 转载_网络流_17        /// tcp接受信息的事件响应方法

中国象棋(网络版) 转载_网络流_17        /// </summary>

中国象棋(网络版) 转载_子线程_18        /// <param name="msg">tcp接收的信息</param>

中国象棋(网络版) 转载_服务器_02        private void _tranfer_ReceiveMsg(string msg)

中国象棋(网络版) 转载_网络流_15中国象棋(网络版) 转载_子线程_16        中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24            /**//*

中国象棋(网络版) 转载_网络流_17             * 1。拆分接收到的信息,判断包头的命令

中国象棋(网络版) 转载_网络流_17             * 2。由于当前接收到的信息线程作用在子线程(receive)上,我们将改变主线程上的窗体信息,

中国象棋(网络版) 转载_网络流_17             * 此时会产生主线程阻塞,此时必须使用窗体的异步调用,使用invoke来对窗体改变

中国象棋(网络版) 转载_网络流_17             * 3。这里涉及到委托传入参数问题

中国象棋(网络版) 转载_子线程_26             * */

中国象棋(网络版) 转载_网络流_17            string [] args = msg.Split('|');

中国象棋(网络版) 转载_网络流_17            if(args[0] == "check")

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24            中国象棋(网络版) 转载_网络流_22{

中国象棋(网络版) 转载_网络流_17                IChessItem ic = GetItemOnPoint( Convert.ToInt32(args[1]),Convert.ToInt32(args[2]));

中国象棋(网络版) 转载_网络流_23中国象棋(网络版) 转载_ip协议_24            object [] os  = 中国象棋(网络版) 转载_网络流_22{ic};

中国象棋(网络版) 转载_网络流_17                this.Invoke(new CheckHandle(Check),os);

中国象棋(网络版) 转载_子线程_26            }

中国象棋(网络版) 转载_网络流_17中国象棋(网络版) 转载_网络流_22

中国象棋(网络版) 转载_子线程_18         }

中国象棋(网络版) 转载_服务器_02}