现在的位置: 首页 > 综合 > 正文

Socket编写一个局域网通信聊天软件

2013年10月13日 ⁄ 综合 ⁄ 共 19034字 ⁄ 字号 评论关闭

 

服务器端:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace ChatServer
{
 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.Label label1;
  private System.Windows.Forms.Label label2;
  private System.Windows.Forms.TextBox txtHost;
  private System.Windows.Forms.TextBox txtPort;
  private System.Windows.Forms.Button btnStart;
  private System.Windows.Forms.Button btnExit;
  private System.Windows.Forms.Label label3;
  private System.Windows.Forms.ComboBox curUserList;
  private System.Windows.Forms.ListBox lstInfo;

  /// <summary>
  /// 必需的设计器变量。
  /// </summary>
  private System.ComponentModel.Container components = null;

  //该服务器默认的监听端口号
  static int port=1234;
  private TcpListener listener;
  private Socket tmpSocket;
  //最多客户端连接数
  static int MaxNum=100;
  //clients数组保持当前在线的client对象
  static ArrayList clients=new ArrayList();

  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  /// <summary>
  /// 清理所有正在使用的资源。
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {
   this.label1 = new System.Windows.Forms.Label();
   this.label2 = new System.Windows.Forms.Label();
   this.txtHost = new System.Windows.Forms.TextBox();
   this.txtPort = new System.Windows.Forms.TextBox();
   this.btnStart = new System.Windows.Forms.Button();
   this.btnExit = new System.Windows.Forms.Button();
   this.label3 = new System.Windows.Forms.Label();
   this.curUserList = new System.Windows.Forms.ComboBox();
   this.lstInfo = new System.Windows.Forms.ListBox();
   this.SuspendLayout();
   //
   // label1
   //
   this.label1.Location = new System.Drawing.Point(0, 16);
   this.label1.Name = "label1";
   this.label1.TabIndex = 0;
   this.label1.Text = "主机号:";
   this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // label2
   //
   this.label2.Location = new System.Drawing.Point(0, 56);
   this.label2.Name = "label2";
   this.label2.TabIndex = 1;
   this.label2.Text = "端口号:";
   this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // txtHost
   //
   this.txtHost.Location = new System.Drawing.Point(104, 16);
   this.txtHost.Name = "txtHost";
   this.txtHost.Size = new System.Drawing.Size(128, 21);
   this.txtHost.TabIndex = 2;
   this.txtHost.Text = "192.168.0.163";
   //
   // txtPort
   //
   this.txtPort.Location = new System.Drawing.Point(104, 56);
   this.txtPort.Name = "txtPort";
   this.txtPort.ReadOnly = true;
   this.txtPort.Size = new System.Drawing.Size(128, 21);
   this.txtPort.TabIndex = 3;
   this.txtPort.Text = "";
   //
   // btnStart
   //
   this.btnStart.Location = new System.Drawing.Point(264, 16);
   this.btnStart.Name = "btnStart";
   this.btnStart.TabIndex = 4;
   this.btnStart.Text = "启动";
   this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
   //
   // btnExit
   //
   this.btnExit.Location = new System.Drawing.Point(264, 56);
   this.btnExit.Name = "btnExit";
   this.btnExit.TabIndex = 5;
   this.btnExit.Text = "退出";
   this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
   //
   // label3
   //
   this.label3.Location = new System.Drawing.Point(24, 136);
   this.label3.Name = "label3";
   this.label3.TabIndex = 6;
   this.label3.Text = "当前在线用户:";
   this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // curUserList
   //
   this.curUserList.Location = new System.Drawing.Point(160, 136);
   this.curUserList.Name = "curUserList";
   this.curUserList.Size = new System.Drawing.Size(121, 20);
   this.curUserList.TabIndex = 7;
   //
   // lstInfo
   //
   this.lstInfo.ItemHeight = 12;
   this.lstInfo.Location = new System.Drawing.Point(24, 184);
   this.lstInfo.Name = "lstInfo";
   this.lstInfo.Size = new System.Drawing.Size(408, 148);
   this.lstInfo.TabIndex = 8;
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(464, 381);
   this.Controls.Add(this.lstInfo);
   this.Controls.Add(this.curUserList);
   this.Controls.Add(this.label3);
   this.Controls.Add(this.btnExit);
   this.Controls.Add(this.btnStart);
   this.Controls.Add(this.txtPort);
   this.Controls.Add(this.txtHost);
   this.Controls.Add(this.label2);
   this.Controls.Add(this.label1);
   this.Name = "Form1";
   this.Text = "ChatServer";
   this.Load += new System.EventHandler(this.Form1_Load);
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  private void Form1_Load(object sender, System.EventArgs e)
  {
  
  }

  /// <summary>
  /// 启动
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void btnStart_Click(object sender, System.EventArgs e)
  {
   txtPort.Text=port.ToString();
   string myip=txtHost.Text;
   try
   {
    IPAddress ipAdd=IPAddress.Parse(myip);
    //创建服务器套接字
    listener=new TcpListener(ipAdd,port);
    //开始监听服务器端口
    listener.Start();
    lstInfo.Items.Add("服务器已经启动,正在监听"+txtHost.Text+":"+txtPort.Text);
    //启动一个线程,执行this.StartListen,在一个独立的进程中执行确认与客户连接的操作
    Thread thread= new Thread(new ThreadStart(this.StartListen));
    thread.Start();
    btnStart.Enabled=false;
   }
   catch(Exception ex)
   {
    lstInfo.Items.Add(ex.Message.ToString());
   }
  }

  /// <summary>
  /// StartListener()方法是在新的线程中进行的,它主要用于当接手到一个客户端请求的时候,
  /// 确认与客户端的连接,并却立刻启动一个新的线程来处理和该客户端的信息交互
  /// </summary>
  private void StartListen()
  {
   while(true)
   {
    try
    {
     //当接收到一个客户端请求时,确认与客户端的连接
     Socket socket = listener.AcceptSocket();
     //用tmpSocket保存发出请求的客户端实例
     tmpSocket=socket;
     if(clients.Count>=MaxNum)
     {
      tmpSocket.Close();
     }
     else
     {
      //启动一个新的线程,执行方法this.ServiceClient,处理用户相应的请求
      Thread clientService=new Thread(new ThreadStart(this.ServiceClient));
      clientService.Start();
     }

    }
    catch(Exception ex)
    {
     lstInfo.Items.Add(ex.Message.ToString());
    }
   }
  }

  /// <summary>
  /// 用于和客户端进行通信
  /// </summary>
  private void ServiceClient()
  {
   //定义一个byte数组,用于接收从客户端发送过来的数据,每次所能结合艘的数据包的最大长度是1024个字节
   byte[] buff=new byte[1024];
   Socket clientSocket = tmpSocket;
   bool keepConnect=true;
   //用循环不断的与客户端进行交互,知道客户端发出“exit”命令,

   while(keepConnect)
   {
    clientSocket.Receive(buff);
    //将字符数组转换成字符串
    string clientCommand=System.Text.Encoding.ASCII.GetString(buff);
    string[] tokens=clientCommand.Split(new char[]{'|'});
    //tokens[0]中保存的自己定义的命令
    if(tokens[0]=="CONN")
    {
     Client _client=new Client(tokens[1],clientSocket);
     clients.Add(_client);
     lstInfo.Items.Add(tokens[1]+" "+"进入");
     //把进入的人加进在线列表
     curUserList.Items.Add(tokens[1]);
     //更新客户端的在线用户列表
     for(int i=0;i<clients.Count;i++)
     {
      Client client=(Client)clients[i];
      //向客户端发送join命令,提示有新的用户进入
      SendToClient(client,"JOIN|"+tokens[1]+"|");
      Thread.Sleep(100);
      string msgUsers="LIST|"+GetUserList();
      
      SendToClient(client,msgUsers);
     }
    }

    if(tokens[0]=="CHAT")
    {
     //向所有当前在线用户发送消息
     for(int i=0;i<clients.Count;i++)
     {
      Client client=(Client)clients[i];
      SendToClient(client,tokens[1]);
     }
    }
    if(tokens[0]=="PRIV")
    {
     //悄悄话
     string sender=tokens[1];
     string receiver=tokens[2];
     string content=tokens[3];
     string message=sender+" send to "+receiver+":  "+content;
     for(int i=0;i<clients.Count;i++)
     {
      Client client=(Client)clients[i];
      if(client.Name.CompareTo(tokens[2])==0)
       SendToClient(client,message);
      if(client.Name.CompareTo(tokens[1])==0)
       SendToClient(client,message);
     }
    }

    if(tokens[0]=="EXIT")
    {
     for(int i=0;i<clients.Count;i++)
     {
      Client client=(Client)clients[i];
      string message=tokens[1]+"下线";
      SendToClient(client,message);
      if(client.Name.CompareTo(tokens[1])==0)
      {
       clients.RemoveAt(i);
       curUserList.Items.Remove(client.Name);
       //向客户端发送QUIT命令,关闭客户端程序
       message="QUIT|";
       SendToClient(client,message);
      }
     }

     //向所有的客户端发送list命令,更新在线用户
     for(int i=0;i<clients.Count;i++)
     {
      Client client=(Client)clients[i];
      string message="LIST|"+GetUserList();
      SendToClient(client,message);
     }
     lstInfo.Items.Add(tokens[1]+"退出");
     clientSocket.Close();
     keepConnect=false;
    }
   }
  }

 

  /// <summary>
  /// 向客户端发送命令请求
  /// </summary>
  /// <param name="client"></param>
  /// <param name="msg"></param>
  private void SendToClient(Client client,string msg)
  {
   System.Byte[]message=System.Text.Encoding.ASCII.GetBytes(msg.ToCharArray());
   client.clientSocket.Send(message,message.Length,0);
  }

  /// <summary>
  /// 获取当前用户列表
  /// </summary>
  /// <returns></returns>
  private string GetUserList()
  {
   string Rtn="";
   for(int i=0;i<clients.Count;i++)
   {
    Client client=(Client)clients[i];
    Rtn=Rtn+client.Name+"|";
   }
   return Rtn;
  }

  /// <summary>
  /// 退出
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void btnExit_Click(object sender, System.EventArgs e)
  {
   Application.Exit();
  }

 

 }

 public class Client
 {
  string name;
  Socket clSocket;

  public Client(string _name,Socket _socket)
  {
   name=_name;
   clSocket=_socket;
  }

  public string Name
  {
   get
   {
    return name;
   }
   set
   {
    name=value;
   }
  }

  public Socket clientSocket
  {
   get
   {
    return clSocket;
   }
   set
   {
    clSocket=value;
   }
  }
 }

}

客户端:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace ChatClient
{
 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.Label label1;
  private System.Windows.Forms.Button button2;
  private System.Windows.Forms.TextBox txtSendContent;
  private System.Windows.Forms.Button btnSend;
  private System.Windows.Forms.ListBox lstContent;
  private System.Windows.Forms.ListBox lstUsers;
  private System.Windows.Forms.CheckBox priCheckBox;
  private System.Windows.Forms.TextBox txtAlias;
  private System.Windows.Forms.Label status;
  private System.Windows.Forms.Button button1;
  private System.Windows.Forms.Label labAlias;

  /// <summary>
  /// 必需的设计器变量。
  /// </summary>
  private System.ComponentModel.Container components = null;
  //与服务器连接
  private TcpClient tcpclient;
  //与服务器数据交互的通道流
  private NetworkStream Strm;
  //用户名
  private string UserAlias;
  //是否为悄悄话
  private bool privatemode=false;

  //
  public TcpClient tcpClient;
  //
  public string Alias="";

 
  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  /// <summary>
  /// 清理所有正在使用的资源。
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {
   this.label1 = new System.Windows.Forms.Label();
   this.txtAlias = new System.Windows.Forms.TextBox();
   this.lstContent = new System.Windows.Forms.ListBox();
   this.lstUsers = new System.Windows.Forms.ListBox();
   this.priCheckBox = new System.Windows.Forms.CheckBox();
   this.txtSendContent = new System.Windows.Forms.TextBox();
   this.btnSend = new System.Windows.Forms.Button();
   this.button2 = new System.Windows.Forms.Button();
   this.status = new System.Windows.Forms.Label();
   this.button1 = new System.Windows.Forms.Button();
   this.labAlias = new System.Windows.Forms.Label();
   this.SuspendLayout();
   //
   // label1
   //
   this.label1.Location = new System.Drawing.Point(0, 8);
   this.label1.Name = "label1";
   this.label1.TabIndex = 0;
   this.label1.Text = "姓名:";
   this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // txtAlias
   //
   this.txtAlias.Location = new System.Drawing.Point(104, 8);
   this.txtAlias.Name = "txtAlias";
   this.txtAlias.TabIndex = 1;
   this.txtAlias.Text = "";
   //
   // lstContent
   //
   this.lstContent.ItemHeight = 12;
   this.lstContent.Location = new System.Drawing.Point(8, 72);
   this.lstContent.Name = "lstContent";
   this.lstContent.Size = new System.Drawing.Size(272, 244);
   this.lstContent.TabIndex = 2;
   //
   // lstUsers
   //
   this.lstUsers.ItemHeight = 12;
   this.lstUsers.Location = new System.Drawing.Point(8, 368);
   this.lstUsers.Name = "lstUsers";
   this.lstUsers.Size = new System.Drawing.Size(72, 88);
   this.lstUsers.TabIndex = 3;
   //
   // priCheckBox
   //
   this.priCheckBox.Location = new System.Drawing.Point(96, 368);
   this.priCheckBox.Name = "priCheckBox";
   this.priCheckBox.TabIndex = 4;
   this.priCheckBox.Text = "悄悄话";
   this.priCheckBox.CheckedChanged += new System.EventHandler(this.priCheckBox_CheckedChanged);
   //
   // txtSendContent
   //
   this.txtSendContent.Location = new System.Drawing.Point(96, 400);
   this.txtSendContent.Name = "txtSendContent";
   this.txtSendContent.Size = new System.Drawing.Size(184, 21);
   this.txtSendContent.TabIndex = 5;
   this.txtSendContent.Text = "";
   //
   // btnSend
   //
   this.btnSend.Enabled = false;
   this.btnSend.Location = new System.Drawing.Point(104, 432);
   this.btnSend.Name = "btnSend";
   this.btnSend.TabIndex = 6;
   this.btnSend.Text = "发送";
   this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
   //
   // button2
   //
   this.button2.Location = new System.Drawing.Point(200, 432);
   this.button2.Name = "button2";
   this.button2.TabIndex = 7;
   this.button2.Text = "离开";
   this.button2.Click += new System.EventHandler(this.button2_Click);
   //
   // status
   //
   this.status.Location = new System.Drawing.Point(8, 328);
   this.status.Name = "status";
   this.status.TabIndex = 8;
   this.status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // button1
   //
   this.button1.Location = new System.Drawing.Point(216, 8);
   this.button1.Name = "button1";
   this.button1.TabIndex = 9;
   this.button1.Text = "连接";
   this.button1.Click += new System.EventHandler(this.button1_Click);
   //
   // labAlias
   //
   this.labAlias.Location = new System.Drawing.Point(96, 40);
   this.labAlias.Name = "labAlias";
   this.labAlias.TabIndex = 10;
   this.labAlias.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(296, 501);
   this.Controls.Add(this.labAlias);
   this.Controls.Add(this.button1);
   this.Controls.Add(this.status);
   this.Controls.Add(this.button2);
   this.Controls.Add(this.btnSend);
   this.Controls.Add(this.txtSendContent);
   this.Controls.Add(this.priCheckBox);
   this.Controls.Add(this.lstUsers);
   this.Controls.Add(this.lstContent);
   this.Controls.Add(this.txtAlias);
   this.Controls.Add(this.label1);
   this.Name = "Form1";
   this.Text = "Login";
   this.Load += new System.EventHandler(this.Form1_Load);
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  
  

  /// <summary>
  /// 加载窗体
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void Form1_Load(object sender, System.EventArgs e)
  {
   /*
   try
   {
    Login dlgLogin=new Login();
    //显示Login对话框
    DialogResult result=dlgLogin.ShowDialog();

    if(result==DialogResult.OK)
    {
     UserAlias=dlgLogin.Alias;
     txtAlias.Text=UserAlias;
     //当Login窗口登陆成功后tcpClient中保存着与服务器的连接
     tcpclient=dlgLogin.tcpClient;
     Strm=tcpclient.GetStream();
     dlgLogin.Close();
    }
    else
    {
     //用户在登陆窗口中点了取消
     lstUsers.Enabled=false;
     txtSendContent.Enabled=false;
     btnSend.Enabled=false;
     dlgLogin.Close();
    }

    //启动一个新的线程,执行方法this.ServerResponse(),响音服务器的消息
    Thread thread=new Thread(new ThreadStart(this.ServerResponse));
    thread.Start();
    //向服务器发送"CONN"请求命令
    string cmd="CONN|"+UserAlias+"|";
    Byte[] outbytes=System.Text.Encoding.ASCII.GetBytes(cmd.ToCharArray());
    Strm.Write(outbytes,0,outbytes.Length);
   }
   catch(Exception ex)
   {
    MessageBox.Show(ex.Message.ToString());
   }

   */
  }

  /// <summary>
  /// 响音服务器的消息
  /// </summary>
  private void ServerResponse()
  {
   byte[] buff=new byte[1024];
   string msg;
   int len;
   try
   {
    if(!Strm.CanRead)
     return;
    //用循环不断的与服务器交互
    while(true)
    {
     len=Strm.Read(buff,0,buff.Length);
     msg=System.Text.Encoding.ASCII.GetString(buff,0,len);
     msg.Trim();
     string[] tokens=msg.Split(new char[]{'|'});

     if(tokens[0]=="LIST")
     {
      status.Text="在线";
      labAlias.Text=UserAlias;
      lstUsers.Items.Clear();
      for(int i=1;i<tokens.Length-1;i++)
       lstUsers.Items.Add(tokens[i].Trim());
     }
     if(tokens[0]=="JOIN")
     {
      lstContent.Items.Add(tokens[1]+" 进入");
     }
     if(tokens[0]=="QUIT")
      break;
     if(tokens[0]!="JOIN"&&tokens[0]!="LIST"&&tokens[0]!="QUIT")
     {
      lstContent.Items.Add(msg);
     }
    }
    tcpclient.Close();
    this.Close();
   }
   catch
   {
    lstContent.Items.Add("网络发生错误");
   }
  }

  /// <summary>
  /// 是否为悄悄话
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void priCheckBox_CheckedChanged(object sender, System.EventArgs e)
  {
   if(priCheckBox.Checked)
    privatemode=true;
   else
    privatemode=false;
  }

  /// <summary>
  /// 发送
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void btnSend_Click(object sender, System.EventArgs e)
  {
   try
   {
    if(!privatemode)
    {
     string message="CHAT|"+UserAlias+":"+txtSendContent.Text+"|";
     txtSendContent.Text="";
     txtSendContent.Focus();
     Byte[] outbytes=System.Text.Encoding.ASCII.GetBytes(message.ToCharArray());
     Strm.Write(outbytes,0,outbytes.Length);
    }
    else
    {
     if(lstUsers.SelectedIndex==-1)
     {
      MessageBox.Show("请选择一个用户");
      return;
     }
     string receiver=lstUsers.SelectedItem.ToString();
     string message="PRIV|"+UserAlias+"|"+receiver+"|"+txtSendContent.Text+"|";
     txtSendContent.Text="";
     txtSendContent.Focus();
     Byte[] outbytes=System.Text.Encoding.ASCII.GetBytes(message.ToCharArray());
     Strm.Write(outbytes,0,outbytes.Length);
    }
   }
   catch
   {
    lstContent.Items.Add("网络发生错误");
   }
  }

  /// <summary>
  /// 离开
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void button2_Click(object sender, System.EventArgs e)
  {
   string message="EXIT|"+UserAlias+"|";
   Byte[] outbytes=System.Text.Encoding.ASCII.GetBytes(message.ToCharArray());
   Strm.Write(outbytes,0,outbytes.Length);
  }

  /// <summary>
  /// 连接
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void button1_Click(object sender, System.EventArgs e)
  {
   try
   {
    tcpClient=new TcpClient();
    //向指定的ip地址的服务器发送连接请求
    tcpClient.Connect(IPAddress.Parse("192.168.0.163"),Int32.Parse("1234"));

    UserAlias=txtAlias.Text;
    Strm=tcpClient.GetStream();
    //启动一个新的线程,执行方法this.ServerResponse(),响音服务器的消息
    Thread thread=new Thread(new ThreadStart(this.ServerResponse));
    thread.Start();
    //向服务器发送"CONN"请求命令
    string cmd="CONN|"+UserAlias+"|";
    Byte[] outbytes=System.Text.Encoding.ASCII.GetBytes(cmd.ToCharArray());
    Strm.Write(outbytes,0,outbytes.Length);

    btnSend.Enabled=true;

   }
   catch(Exception ex)
   {
    MessageBox.Show(ex.Message.ToString());
   }
  }

 

 }
}

 

抱歉!评论已关闭.