zoukankan      html  css  js  c++  java
  • x01.Weiqi.3 网络对弈

    为简化,只实现了两个用户的网络对弈。但在此基础上,即使去实现一个具有商业价值的网络对弈程序,应该也不是什么难事。毕竟,核心的问题已经解决了。
    首先,是服务端。新建一个 WinForm 项目 Server。在主窗口中,添加一个按钮m_ButtonStartServer,双击,在 click 事件中,实现TcpListener 的诸多功能。
    主窗口文件 MainForm.cs 内容如下:
    MainForm
    namespace Server
    {
    publicpartialclass MainForm : Form
    {
    TcpListener m_TcpListener;
    List
    <User> m_Users =new List<User>(); //为简化,只作 2 想

    public MainForm()
    {
    InitializeComponent();
    }

    privatevoid ButtonStartServer_Click(object sender, EventArgs e)
    {
    IPAddress ip
    = Dns.GetHostAddresses(Dns.GetHostName())[0];
    m_TcpListener
    =new TcpListener(ip, 51000);
    m_TcpListener.Start();

    ThreadStart threadStart
    =new ThreadStart(ListenClient);
    Thread thread
    =new Thread(threadStart);
    thread.Start();

    MessageBox.Show(
    "Start server success!");
    }

    void ListenClient()
    {
    while (true)
    {
    TcpClient client
    =null;
    try
    {
    client
    = m_TcpListener.AcceptTcpClient();
    }
    catch
    {
    break; // 以此退出?
    }
    User user
    =new User(client);
    m_Users.Add(user);

    ParameterizedThreadStart ptStart
    =new ParameterizedThreadStart(ReceiveData);
    Thread thread
    =new Thread(ptStart);
    thread.Start(user);
    }
    }

    void ReceiveData(object u)
    {
    User user
    = (User)u;
    while (true)
    {
    string data = user.Reader.ReadLine();
    for (int i =0; i <2; i++)
    {
    string color = i %2==0?"black" : "white";
    m_Users[i].Writer.WriteLine(
    string.Format("{0},{1}", color, data));
    m_Users[i].Writer.Flush();
    }
    }
    }

    protectedoverridevoid OnClosing(CancelEventArgs e)
    {
    base.OnClosing(e);

    foreach (var item in m_Users)
    {
    item.Client.Close();
    }
    m_TcpListener.Stop();
    }
    }
    }
    其中,User 是为方便用户管理而添加的类。
    代码文件 User.cs 内容如下:
    User
    namespace Server
    {
    class User
    {
    public TcpClient Client { get; privateset; }
    public StreamReader Reader { get; privateset; }
    public StreamWriter Writer { get; privateset; }
    public User(TcpClient client)
    {
    this.Client = client;
    NetworkStream netStream
    = client.GetStream();
    Reader
    =new StreamReader(netStream, System.Text.Encoding.UTF8);
    Writer
    =new StreamWriter(netStream, System.Text.Encoding.UTF8);
    }
    }
    }
    如此,服务端就算完成。
    客户端,直接从 BoardBase 继承,类名为:InetBoard。
    代码文件 InetBoard.cs 内容如下:
    InetBoard
    namespace x01.Weiqi.Board
    {
    publicclass InetBoard : BoardBase
    {
    int m_Col =-1, m_Row =-1, m_StepCount =-1;
    string m_Color =string.Empty;
    TcpClient m_Client
    =null;
    StreamWriter m_Writer
    =null;
    StreamReader m_Reader
    =null;
    int m_Count =0;
    System.Windows.Forms.Timer m_Timer
    =new System.Windows.Forms.Timer();

    public InetBoard(int size =38)
    :
    base(size)
    {
    m_Timer.Tick
    +=new EventHandler(Timer_Tick);
    m_Timer.Start();

    InitClient();
    }

    void Timer_Tick(object sender, EventArgs e)
    {
    Draw();
    }

    void Draw()
    {
    int col = m_Col;
    int row = m_Row;
    if (NotIn(col, row))
    {
    return;
    }
    DrawChess(col, row);
    Eat(col, row);

    m_Count
    ++;
    }

    void InitClient()
    {
    // 测试,取主机即可。实际,应为服务器域名
    m_Client =new TcpClient(Dns.GetHostName(), 51000);
    m_Writer
    =new StreamWriter(m_Client.GetStream(), Encoding.UTF8);
    m_Reader
    =new StreamReader(m_Client.GetStream(), Encoding.UTF8);

    Thread thread
    =new Thread(new ThreadStart(Receive));
    thread.Start();
    }

    void Receive()
    {
    while (true)
    {
    string data = m_Reader.ReadLine();
    string[] step = data.Split(',');
    m_Color
    = step[0];
    m_Col
    =int.Parse(step[1]);
    m_Row
    =int.Parse(step[2]);
    m_StepCount
    =int.Parse(step[3]);
    }
    }

    void Send(string data)
    {
    m_Writer.WriteLine(data);
    m_Writer.Flush();
    }

    protectedoverridevoid OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
    {
    base.OnMouseLeftButtonDown(e);

    if (m_Color =="black"&& IsBlack !=false)
    {
    return;
    }

    if (m_Color =="white"&& IsBlack ==false)
    {
    return;
    }

    int col = (int)e.GetPosition(this).X / ChessSize;
    int row = (int)e.GetPosition(this).Y / ChessSize;

    string data =string.Format("{0},{1},{2}", col, row, m_Count +1);
    Send(data);
    }
    }
    }
    用户控件 Chess 只能在 STA 中处理,故添加了一个 Timer。逻辑不复杂,不详叙。
    用法:
    1. 运行Server,效果图如下:
    2. 启动两个 x01.Weiqi,从菜单中选择 Inet 项。用户1和2的运行效果图如下:

    源代码可从 http://www.cnblogs.com/china_x01  的 download\code\x01.Weiqi 获取。

    Copyright (c) 2011 by x01(china_x01@qq.com),未经许可,请勿转载。

  • 相关阅读:
    很简单的企业管理器我写程序的方式,几个自定义控件。
    当OO遇到了持久化?!
    [自定义服务器控件] 第一步:文本框。
    [面向过程——老酒换新瓶] (一)开篇:是面向过程还是面向对象?
    个人理财小助手 —— 设计思路、功能说明
    《Head First 设计模式》 终于出中文版了。
    其实添加数据也可以这样简单——表单的第一步抽象(针对数据访问层)《怪怪设计论: 抽象无处不在 》有感
    基类、接口的应用——表单控件:一次添加、修改一条记录,一次修改多条记录。(上)
    其实添加数据也可以这样简单——表单的第三步抽象(针对UI及后置代码)
    转帖:客户端表单通用验证checkForm(oForm) js版
  • 原文地址:https://www.cnblogs.com/china_x01/p/2048712.html
Copyright © 2011-2022 走看看