中国象棋(网络版)

最近时间有点忙,本来象棋游戏是有一个网络版本的,但是由于最近时间比较忙,一直没发出来.
最近有一些朋友希望看到网络版象棋,本来这个是学生将做的项目,这里我把这个DEMO给大家,相互学习.

网络象棋,不得不说一下TCP/IP协议,这其实是两个协议,即tcp协议和ip协议。
所谓IP协议,IP协议是在网络层的协议.它主要完成数据包的发送作用。
所谓TCP协议,TCP协议也是建立在IP协议之上的,不过TCP协议是可靠的.按照顺序发送的。
所以正是由于他们的特性,使得他们一起可以使我们网络数据传输可靠。一般我们常说的TCP/IP“三次握手”,其实也就是第一步客户机向服务器发送一个TCP数据包,表示请求建立连接,第二步服务器接收到请求数据包以后再向客户端发送一次响应数据包,第三步客户机接收到以后再想服务器发送一次确认数据包。服务器接受到以后,我们的连接也就成功。

那么socket(套接字)呢?其实也就是两台机器的远程节点,它的操作也包括,打开,关闭,读写等等。
具体的呢,大家可以去看一下关于TCP/IP的书,这里我就不予累赘。

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

这里呢主要是采用原来单机版象棋进行功能扩展的,其实所谓网络版本,也就是将原本在电脑的输入操作换做网络数据输入,所以其他算法和设计都基本一样。这里我讲一下具体实现的网络部分
首先需要创建网络服务器和客户机的登陆部分
 clip_image001.jpg
分为服务器和客户机登陆以后:
客户端:
None.gif                TcpClient client  =   new  TcpClient();
None.gif                IPAddress ip 
=  IPAddress.Parse( this .tbIP.Text);
None.gif                
int  port  =  Convert.ToInt32( tbPort.Text);
None.gif                client.Connect(ip,port);
None.gif                Flag.PlayerType 
=  Enums.ChessType.red;
None.gif                TcpTransfer tranfer 
=   new  TcpTransfer(client);

服务器则是需要建立监听:
None.gif int  port  =  Convert.ToInt32( tbPort.Text);
None.gif                TcpListener listener 
=   new  TcpListener(port);
None.gif                listener.Start();
None.gif                TcpClient client 
=  listener.AcceptTcpClient();
None.gif                Flag.PlayerType 
=  Enums.ChessType.blue;
None.gif                TcpTransfer tranfer 
=   new  TcpTransfer(client);
None.gif

这里数据传输呢,封装在TcpTransfer类中
ExpandedBlockStart.gif ContractedBlock.gif /**/ /// <summary>
InBlock.gif    
/// tcp传输控制类
ExpandedBlockEnd.gif    
/// </summary>

None.gif      public   class  TcpTransfer 
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 接收信息事件的委托
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public delegate void ReceiveMsgHandle(string msg); 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 接收信息事件
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public event ReceiveMsgHandle ReceiveMsg;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 接收信息事件激活方法
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <param name="msg"></param>

InBlock.gif        private void OnReceive(string msg)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if(ReceiveMsg !=null)
InBlock.gif                ReceiveMsg(msg);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private TcpClient _client;
InBlock.gif        
public TcpTransfer(TcpClient client)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            _client 
= client;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 发送信息
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <param name="msg"></param>

InBlock.gif        public void Send(string msg)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//获取网络流
InBlock.gif
            NetworkStream ns = _client.GetStream();
InBlock.gif            
//将要发送的字符串转换为字节数组
InBlock.gif
            byte [] bytes = System.Text.Encoding.Default.GetBytes( msg );
InBlock.gif            
//写入网络流
InBlock.gif
            ns.Write( bytes,0,bytes.Length );
InBlock.gif            ns.Flush();
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 接收信息
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public void Receive()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//获取网络流
InBlock.gif
            NetworkStream ns = _client.GetStream();
InBlock.gif            
while(true)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
byte [] bytes = new byte[512];
InBlock.gif                
int size = 0;
InBlock.gif                
InBlock.gif                
try
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
//刷新流
InBlock.gif
                    ns.Flush();
InBlock.gif                    
//从网络流里读取信息到byte[]
InBlock.gif
                    size = ns.Read(bytes,0,bytes.Length);
ExpandedSubBlockEnd.gif                }

InBlock.gif                
catch
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    System.Windows.Forms.MessageBox.Show(
"tcp连接出现故障!程序异常的退出!");
InBlock.gif                    System.Windows.Forms.Application.Exit();
ExpandedSubBlockEnd.gif                }

InBlock.gif                
ExpandedSubBlockStart.gifContractedSubBlock.gif                
/**//*
InBlock.gif                 * 由于socket连接后作为网络传输的会有很多异常
InBlock.gif                 * 在这里我们只是简单的做了一点处理,当然,在实际开发中socket异常的处理绝不仅仅如此简单
InBlock.gif                 * 如果断开连接,有可能会出现一直接收0个字节问题
InBlock.gif                 * 如果接收到0个字节,则退出循环
ExpandedSubBlockEnd.gif                 * 
*/

InBlock.gif                
if(size<=0break;
InBlock.gif
InBlock.gif                
//将接收到的字节转换为字符串
InBlock.gif
                string msg = System.Text.Encoding.Default.GetString(bytes);
InBlock.gif
InBlock.gif                OnReceive( msg );
InBlock.gif
InBlock.gif                
//当前线程休眠100毫秒
InBlock.gif
                System.Threading.Thread.Sleep(100);
InBlock.gif
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

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

None.gif          private   delegate   bool  CheckHandle(IChessItem ic);
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary>
InBlock.gif        
/// 移动操作的异步委托
ExpandedBlockEnd.gif        
/// </summary>

None.gif          private   delegate   bool  MoveToHandle( int  x, int  y);
ExpandedBlockStart.gifContractedBlock.gif        
/**/ /// <summary>
InBlock.gif        
/// 吃棋子的异步委托
ExpandedBlockEnd.gif        
/// </summary>

None.gif          private   delegate   bool  EatHandle(IChessItem ic);
在我们TCP事件里面,则采用invoke异步的模式进行委托
ExpandedBlockStart.gif ContractedBlock.gif          /**/ /// <summary>
InBlock.gif        
/// tcp接受信息的事件响应方法
InBlock.gif        
/// </summary>
ExpandedBlockEnd.gif        
/// <param name="msg">tcp接收的信息</param>

None.gif          private   void  _tranfer_ReceiveMsg( string  msg)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif            
/**//*
InBlock.gif             * 1。拆分接收到的信息,判断包头的命令
InBlock.gif             * 2。由于当前接收到的信息线程作用在子线程(receive)上,我们将改变主线程上的窗体信息,
InBlock.gif             * 此时会产生主线程阻塞,此时必须使用窗体的异步调用,使用invoke来对窗体改变
InBlock.gif             * 3。这里涉及到委托传入参数问题
ExpandedSubBlockEnd.gif             * 
*/

InBlock.gif            
string [] args = msg.Split('|');
InBlock.gif            
if(args[0== "check")
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                IChessItem ic 
= GetItemOnPoint( Convert.ToInt32(args[1]),Convert.ToInt32(args[2]));
ExpandedSubBlockStart.gifContractedSubBlock.gif            
object [] os  = dot.gif{ic};
InBlock.gif                
this.Invoke(new CheckHandle(Check),os);
ExpandedSubBlockEnd.gif            }

InBlock.gifdot.gif
ExpandedBlockEnd.gif         }

None.gif}
None.gif

其余的呢和前面单机版本差不多,这里就不再多讲了
这里呢有一些地方,如socket传输等,实际的项目里面异常和其他的判断处理远远比这复杂,我这里只是简单的做一点处理,呵呵,本来也只是教学用的^_^

Source  Demo

转载于:https://www.cnblogs.com/KeithDan/archive/2007/07/08/810222.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值