很早之前和一个朋友一齐做的, 可现在都毕业了,没人一齐做。放弃这个小念头,开源给大家参考一下。 希望一些高手可以完善他,呵呵· 这是服务器··socket类库 // [10/18/2010 cheng] namespace Sever_net { public class SocketTcp { #region 字段定义 /// <summary> /// 服务器程序使用的端口,默认为27308 /// </summary> private int _port = 27308; /// <summary> /// 接收数据缓冲区大小64K /// </summary> private const int _maxPacket = 64 * 1024; /// <summary> /// 服务器端的监听器 /// </summary> private TcpListener _tcpl = null; /// <summary> /// 保存所有客户端会话的哈希表 /// </summary> private Hashtable _transmit_tb = new Hashtable(); /// <summary> /// 服务器IP /// </summary> private IPAddress _ip = null; /// <summary> /// 信息 /// </summary> private string msg = string.Empty; /// <summary> /// 记录玩家名 /// </summary> private List<object> playerName = new List<object>(); /// <summary> /// 牌信息 /// </summary> private string cardsMsg; /// <summary> /// 记录牌 /// </summary> private List<int> cards = new List<int>(); /// <summary> /// 玩家信息 /// </summary> private string Players; #endregion #region 建立监听 /// <summary> /// 启动监听,轮询监听客户机请求并将客户端套接字存入转发表 /// </summary> public void StartUp() { //IPAddress _ip = Dns.GetHostAddresses(Dns.GetHostName())[0];//可能有多个,此时的IP是本地IP try { this.RandCards(); IPAddress[] arrIPAddresses = Dns.GetHostAddresses(Dns.GetHostName()); foreach (IPAddress ip in arrIPAddresses) { if (ip.AddressFamily.Equals(AddressFamily.InterNetwork)) { _ip = ip; } } msg = "服务器已启动,正在监听....../n"; Console.WriteLine(msg); _tcpl = new TcpListener(_ip, _port); _tcpl.Start();//开始侦听传入的连接请求。 msg = "服务器IP:" + _ip.ToString() + " 端口号:" + _port.ToString(); Console.WriteLine(msg); while (true) { byte[] packetBuff = new byte[_maxPacket];// 接收数据缓冲区大小64K Socket newClient = _tcpl.AcceptSocket();//本地TcpListener 接受新的请求 //返回的 Socket 是使用远程主机的 IP 地址和端口号初始化的 newClient.Receive(packetBuff);//将接受的远程SOCKET,将数据存入接受缓冲区 string userName = Encoding.Default.GetString(packetBuff).TrimEnd('/0'); //验证是否为唯一用户,有了就发送失败命令给请求客户 if (_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(userName)) { newClient.Send(Encoding.Default.GetBytes("@userError")); continue; } else { newClient.Send(Encoding.Default.GetBytes("@loginSuccess")); } //将新连接加入转发表并创建线程为其服务 _transmit_tb.Add(userName, newClient); playerName.Add(userName); //----------------------- string svrlog = string.Format("[系统消息]玩家: {0} 已连接 当前在线人数: {1} 登录时间:{2}", userName, _transmit_tb.Count, DateTime.Now); Console.WriteLine(svrlog); //------------------------ //进入命令函数 //人数上限 int users = 6; if (_transmit_tb.Count == users) { Socket player2 = _transmit_tb[playerName[1]] as Socket; msg = playerName[1] + "@selectCards|"; player2.Send(Encoding.Default.GetBytes("@selectCards|")); Console.WriteLine(msg); foreach (string name in _transmit_tb.Keys) { Thread clientThread = new Thread(new ParameterizedThreadStart(ThreadFunc)); clientThread.IsBackground = true; clientThread.Start(name); } this.Player_Names();//玩家信息 } } } catch (Exception ex) { Console.WriteLine("服务器发生异常,消息:" + ex.Message); this.Close(); } } /// <summary> /// 关闭监听器并释放资源 /// </summary> public void Close() { if (_tcpl != null) { _tcpl.Stop();//如果不为空 就停止 tcplistener } //关闭客户端连接并清理资源 if (_transmit_tb.Count != 0)//客户端会话的哈希表 { foreach (Socket session in _transmit_tb.Values) { session.Shutdown(SocketShutdown.Both); } _transmit_tb.Clear(); _transmit_tb = null; } } #endregion #region 提取命令 /// <summary> /// 提取命令 /// </summary> /// <param name="obj"></param> private void ThreadFunc(object obj) { //通过转发表得到当前用户套接字 //玩家索引 int i = 4; int j = 1; Socket clientSkt1 = _transmit_tb[playerName[j]] as Socket; Socket clientSkt2 = _transmit_tb[playerName[i]] as Socket; Socket clientSkt = _transmit_tb[obj] as Socket; while (true) { try { //仅有两种情况,一为可以识别的命令格式,否则为要求转发给指定用户的用户名。 byte[] _cmdBuff = new byte[_maxPacket]; clientSkt.Receive(_cmdBuff); string _cmd = Encoding.Default.GetString(_cmdBuff).TrimEnd('/0'); switch (_cmd) { case "@selectKing": { clientSkt.Send(Encoding.Default.GetBytes("@selectCards1|")); msg = obj.ToString() + "@selectCards1|"; Console.WriteLine(msg); clientSkt2.Send(Encoding.Default.GetBytes("@selectCards-1|")); msg = playerName[i] + "@selectCards-1|"; Console.WriteLine(msg); break; } case "@selectTraitor": { clientSkt.Send(Encoding.Default.GetBytes("@selectCards-1|")); msg = obj.ToString() + "@selectCards-1|"; Console.WriteLine(msg); clientSkt2.Send(Encoding.Default.GetBytes("@selectCards1|")); msg = playerName[i] + "@selectCards1|"; Console.WriteLine(msg); break; } case "@Ready": { foreach (DictionaryEntry de in _transmit_tb) { string _clientName = de.Key as string; Socket _clientSkt = de.Value as Socket; _clientSkt.Send(Encoding.Default.GetBytes("@HeroCards|" + cardsMsg + "|" + Players)); msg = _clientName.ToString() + "@HeroCards|" + cardsMsg + "|" + Players; Console.WriteLine(msg); } break; } case "@SelectHeroCard": { string _receiver = null; string[] temp = new string[2]; byte[] _receiverBuff = new byte[_maxPacket]; clientSkt.Receive(_receiverBuff); _receiver = Encoding.Default.GetString(_receiverBuff).TrimEnd('/0'); if(_receiver.Contains("|")) { temp = _receiver.Split('|'); if (temp[1].Equals("@NextRoundKing")) { clientSkt1.Send(Encoding.Default.GetBytes("@selectCards2|")); msg = playerName[j] + "@selectCards2|"; Console.WriteLine(msg); } if (temp[1].Equals("@NextRoundTraitor")) { clientSkt2.Send(Encoding.Default.GetBytes("@selectCards2|")); msg = playerName[i] + "@selectCards2|"; Console.WriteLine(msg); } foreach (DictionaryEntry de in _transmit_tb) { string _clientName = de.Key as string; Socket _clientSkt = de.Value as Socket; _clientSkt.Send(Encoding.Default.GetBytes("@SelectHeroCard|" + temp[0])); msg = _clientName + temp[0]; Console.WriteLine(msg); } } else { foreach (DictionaryEntry de in _transmit_tb) { string _clientName = de.Key as string; Socket _clientSkt = de.Value as Socket; _clientSkt.Send(Encoding.Default.GetBytes("@SelectHeroCard|" + _receiver)); msg = _clientName + _receiver; Console.WriteLine(msg); } } break; } } } catch (SocketException) { _transmit_tb.Remove(obj); string svrlog = string.Format("[系统消息]玩家 {0} 的客户端在 {1} 意外终止!当前在线人数:{2}/r/n/r/n", obj, DateTime.Now, _transmit_tb.Count); //向所有客户机发送系统消息 foreach (DictionaryEntry de in _transmit_tb) { string _clientName = de.Key as string; Socket _clientSkt = de.Value as Socket; _clientSkt.Send(Encoding.Default.GetBytes(svrlog)); } Console.WriteLine(); Thread.CurrentThread.Abort(); } } } /// <summary> /// 玩家信息连接 /// </summary> private void Player_Names() { for (int i = 0; i < playerName.Count;i++ ) { Players += playerName[i] + "-"; } } /// <summary> /// 随机分配武将牌 /// </summary> private void RandCards() { int rand = 0; int n = 0; while (n <= 18) { Random rd = new Random(); rand = rd.Next(0, 25); if (isUsed(rand)) { rand = rd.Next(0, 25); continue; } else { cards.Add(rand); n++; } } foreach (int i in cards) { cardsMsg += i.ToString() + "-"; } } /// <summary> /// 去除重复 /// </summary> /// <param name="r"></param> /// <returns></returns> private bool isUsed(int r) { foreach (int i in cards) { if (r == i) return true; } return false; } #endregion } 服务器 using Sever_net; // [10/18/2010 cheng] namespace Sango_Sever { class Program { static void Main(string[] args) { SocketTcp socket_tcp = new SocketTcp(); //开始监听部分 try { socket_tcp.StartUp(); } catch (Exception e) { Console.WriteLine("/n服务器发生异常,消息:" + e.Message); socket_tcp.Close(); } } } } 客户端 /// <summary> /// 牌枚举 /// </summary> public enum Cards { King = 0, Traitor = 1 } public class SanguoCmd { public static string SK = "@selectKing";//选择主公 public static string ST = "@selectTraitor";//选择内奸 public static string Ready = "@Ready";//准备游戏 public static string SHC = "@SelectHeroCard";//选择英雄 } public class spMsg { /// <summary> /// 提取命令切割1 /// </summary> /// <param name="msg"></param> /// <returns></returns> public List<string> sp_msg1(string msg) { List<string> teams = new List<string>(); string[] temp = new string[2]; temp = msg.Split('|'); teams.AddRange(temp); return teams; } /// <summary> /// 提取命令切割2 /// </summary> /// <param name="msg"></param> /// <returns></returns> public List<string> sp_msg2(string msg) { List<string> teams = new List<string>(); string[] temp = new string[26];//分开玩家名 temp = msg.Split('-'); teams.AddRange(temp); return teams; } } /// <summary> /// TCP连接类,成功连接返回TcpClient引用,否则返回null /// </summary> class TCPConnection { #region 定义变量 /// <summary> /// IP地址 /// </summary> private IPAddress _ip = null; /// <summary> /// TCP连接端口 /// </summary> private int _port; /// <summary> /// TCP连接接口 /// </summary> private TcpClient _tcpc = null; #endregion /// <summary> /// TCP连接构造函数 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> public TCPConnection(IPAddress ip, int port) { _ip = ip; _port = port; } /// <summary> /// TCP连接方法 /// </summary> /// <returns></returns> public TcpClient Connect() { try { _tcpc = new TcpClient(); _tcpc.Connect(_ip, _port);//连接到服务 } catch (Exception) { return null; } return _tcpc; } } 登录源码 public FrmSangoLogin() { InitializeComponent(); } /// <summary> /// IP地址 /// </summary> private IPAddress _ipAddr; private void btnExit_Click(object sender, EventArgs e) { this.Dispose(); } private void btnLogin_Click(object sender, EventArgs e) { //验证数据合法性 if (!ValidateInfo()) { return; } int port = int.Parse("27308"); //向服务器发出连接请求 TCPConnection conn = new TCPConnection(_ipAddr,port); TcpClient _tcpc = conn.Connect(); if (_tcpc == null) { MessageBox.Show("无法连接到服务器,请重试!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else { NetworkStream netstream = _tcpc.GetStream();//提供用于访问网络的基本数据流 //向服务器发送用户名以确认身份 netstream.Write(Encoding.Default.GetBytes(txtUser.Text.Trim()), 0, Encoding.Default.GetBytes(txtUser.Text).Length); //得到登录结果 byte[] buffer = new byte[50]; netstream.Read(buffer, 0, buffer.Length);//该方法将数据读入 buffer 参数并返回成功读取的字节数。如果没有可以读取的数据,则 Read 方法返回 0。 string connResult = Encoding.Default.GetString(buffer).TrimEnd('/0'); if (connResult.Equals("cmd::Failed")) { MessageBox.Show("您的用户名已经被使用,请尝试其他用户名!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); lblLoading.Visible = false; return; } else { IPAddress svrskt = _ipAddr; this.Hide(); FrmSangoHero frmsanguohero = new FrmSangoHero(txtUser.Text, netstream, svrskt, connResult); frmsanguohero.Show(); lblLoading.Visible = true; } } } //检查信息 private bool ValidateInfo() { if (txtUser.Text.Trim() == string.Empty) { MessageBox.Show("请填写用户名!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } if (!IPAddress.TryParse(txt_ip.Text, out _ipAddr)) { MessageBox.Show("IP地址不合法!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } return true; } private void FrmSangoLogin_FormClosing(object sender, FormClosingEventArgs e) { this.Dispose(); } } 选将源码 public partial class FrmSangoHero : Form { #region 定义变量 private Thread _receiveThread = null;//接受消息线程 private string _username = null;//当前用户名 private IPAddress _svrskt = null;//服务器套接字符串形式,从登陆窗体得到 private NetworkStream _nws = null;//用于接收和发送的网络流,从登陆窗体得到 private string _connResult = null;//得到登陆结果,从登陆窗体得到 private const int _maxPacket = 64 * 1024;//包最大大小 private List<Panel> SelectCard = new List<Panel>();//记录角色牌 private List<Panel> SelectHeroCards = new List<Panel>();//记录所选武将牌 private Panel panSelectCard; //牌容器 private string _cmd; //命令 private List<string> get_Result = new List<string>();//复合命令 private spMsg msg = new spMsg();//接收信息 private List<string> Players = new List<string>();//记录玩家名 private List<string> HeroCards = new List<string>();//记录武将牌 private int SelectCount = -1; //选择武将牌上限 private int SelectHeroCardCount = 0;//确认所选武将牌上限 private int isUp = 0;//武将牌上升上限 private int isSelect = 0;//确认所选武将牌次数 private int heroX = 0;//确认所选武将牌X坐标 private int HeroN = 0;//所选武将牌的数量 private string _music_path = Application.StartupPath + "/" + "Music" + "/" + "SangoGame.mp3";//背景音乐路径 #endregion /// <summary> /// 用户名,字节流,IP地址,登录结果 /// </summary> /// <param name="userName"></param> /// <param name="nws"></param> /// <param name="svrskt"></param> /// <param name="connResult"></param> public FrmSangoHero(string userName, NetworkStream nws, IPAddress svrskt, string connResult) { InitializeComponent(); _username = userName; _nws = nws; _svrskt = svrskt; _connResult = connResult; } private void FrmSangoGame_Load(object sender, EventArgs e) { _receiveThread = new Thread(new ThreadStart(ReceiveMsg)); _receiveThread.IsBackground = true; _receiveThread.Start(); MusicPlayer.URL = _music_path; } private void FrmSangoGame_FormClosing(object sender, FormClosingEventArgs e) { Application.Exit(); this.Dispose(); } #region 添加牌构造方法 /// <summary> /// 增加牌,x,y坐标,牌名,牌索引,牌图片集合 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="name"></param> /// <param name="index"></param> /// <param name="img"></param> /// <returns></returns> private Panel addCards(int x, int y, string name, object index, ImageList img) { panSelectCard = new Panel(); panSelectCard.Name = name; panSelectCard.Size = new System.Drawing.Size(100, 145); panSelectCard.Location = new System.Drawing.Point(x, y); panSelectCard.BackgroundImage = img.Images[(int)(index)]; return panSelectCard; } #endregion #region 牌显示 /// <summary> /// 显示角色牌 /// </summary> private void ShowSelectCards() { panSelectCards.Visible = true; panSelectCard = addCards(0, 10, "panKing", Cards.King, imgCards); panCards.Controls.Add(panSelectCard); SelectCard.Add(panSelectCard); panSelectCard = addCards(100, 10, "panTraitor", Cards.Traitor, imgCards); panCards.Controls.Add(panSelectCard); SelectCard.Add(panSelectCard); foreach (Panel i in SelectCard) { i.MouseDown += Cards_MouseDown; } } /// <summary> /// 显示武将牌 /// </summary> private void ShowHeroCards() { int n = 0; HeroCards_paixu(0, 8, panHeroCards1); HeroCards_paixu(9, 17, panHeroCards2); foreach (Panel i in SelectHeroCards) { i.MouseDown += HeroCards_MouseDown; } try { foreach (Label j in panHeroCards.Controls) { if (n >= Players.Count - 1) break;//测试 j.Text = Players[n]; n++; } } catch { } } #endregion private void Cards_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; foreach (Panel i in SelectCard) { if (p.Name == i.Name) { if (i.Tag == null) { i.Location = new System.Drawing.Point(i.Location.X, i.Location.Y - 10); i.Tag = "isUp"; break; } if ((string)i.Tag == "isUp") { i.Location = new System.Drawing.Point(i.Location.X, i.Location.Y + 10); i.Tag = null; break; } } } if (SelectCard[0].Tag != null && SelectCard[1].Tag != null) { btnOk.Enabled = false; lblError.Text = "只能选一个角色"; } else { btnOk.Enabled = true; lblError.Text = string.Empty; } } #region 提取命令 /// <summary> /// 接收命令 /// </summary> private void ReceiveMsg() { while(true) { Byte[] packet = new byte[_maxPacket]; _nws.Read(packet, 0, packet.Length); _cmd = Encoding.Default.GetString(packet).TrimEnd('/0'); get_Result = msg.sp_msg1(_cmd); switch (get_Result[0]) { case "@selectCards": MethodInvoker ShowCards = new MethodInvoker(ShowSelectCards); this.BeginInvoke(ShowCards); break; case "@selectCards1": SelectHeroCardCount = 1; SelectCount = 1; isUp = 0; _nws.Write(Encoding.Default.GetBytes(SanguoCmd.Ready.Trim()), 0, SanguoCmd.Ready.Length); MessageBox.Show("已进入选牌模式!"); break; case "@selectCards-1": SelectHeroCardCount = -1; SelectCount = -1; _nws.Write(Encoding.Default.GetBytes(SanguoCmd.Ready.Trim()), 0, SanguoCmd.Ready.Length); MessageBox.Show("已进入选牌模式!"); break; case "@selectCards2": SelectHeroCardCount = 2; SelectCount = 1; isUp = 0; MessageBox.Show("已进入下一轮选牌模式!"); break; case "@HeroCards": Players = msg.sp_msg1(get_Result[2]); Players = msg.sp_msg2(Players[0]); HeroCards = msg.sp_msg2(get_Result[1]); MethodInvoker ShowHreos = new MethodInvoker(ShowHeroCards); this.BeginInvoke(ShowHreos); break; case "@SelectHeroCard": MethodInvoker Select = new MethodInvoker(Select_HeroCard); this.BeginInvoke(Select); break; } } } #endregion /// <summary> /// 剔除已选的武将牌 /// </summary> private void Select_HeroCard() { foreach (Panel i in panHeroCards1.Controls) { if (get_Result[1] == "@" + i.Name) { panHeroCards1.Controls.Remove(i); } } foreach (Panel j in panHeroCards2.Controls) { if (get_Result[1] == "@" + j.Name) { panHeroCards2.Controls.Remove(j); } } } private void HeroCards_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; foreach (Panel i in SelectHeroCards) { if(p.Name == i.Name) { if (i.Tag == null) { if (isUp >= SelectCount) return; i.Location = new System.Drawing.Point(i.Location.X, i.Location.Y - 10); i.Tag = "isUp"; isUp++; btnHOK.Visible = true; break; } else if((string)i.Tag == "isUp") { i.Location = new System.Drawing.Point(i.Location.X, i.Location.Y + 10); i.Tag = null; isUp--; btnHOK.Visible = false; break; } } } } /// <summary> /// 武将牌排序,起,止,武将容器 /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="p"></param> private void HeroCards_paixu(int start,int end,Panel p) { int x = 0; int index = 0; string name = string.Empty; for (int i = start; i < end; i++) { index = int.Parse(HeroCards[i]); name = imgHero.Images.Keys[index].ToString(); panSelectCard = addCards(x, 10, name, index, imgHero); p.Controls.Add(panSelectCard); SelectHeroCards.Add(panSelectCard); x += 100; } } private void btnOk_Click(object sender, EventArgs e) { if(SelectCard[0].Name=="panKing" && SelectCard[0].Tag!=null) { _nws.Write(Encoding.Default.GetBytes(SanguoCmd.SK.Trim()), 0,SanguoCmd.SK.Length); } if (SelectCard[1].Name == "panTraitor" && SelectCard[1].Tag != null) { _nws.Write(Encoding.Default.GetBytes(SanguoCmd.ST.Trim()), 0, SanguoCmd.ST.Length); } panSelectCards.Visible = false ; panHeroCards.Visible = true; } private void btnHOK_Click(object sender, EventArgs e) { HeroN++; foreach (Panel i in SelectHeroCards) { if ((string)i.Tag == "isUp") { isSelect++; isUp = 0; i.Tag = null; btnHOK.Visible = false; i.Location = new Point(heroX, 0); PHC1.Controls.Add(i); heroX += 100; _nws.Write(Encoding.Default.GetBytes(SanguoCmd.SHC.Trim()),0,SanguoCmd.SHC.Length); _nws.Write(Encoding.Default.GetBytes("@" + i.Name.Trim()), 0, i.Name.Trim().Length + 1); break; } } if (isSelect >= SelectHeroCardCount) { if (_username == lblPlayer5.Text.Trim()) _nws.Write(Encoding.Default.GetBytes("|@NextRoundTraitor"), 0, 18); if (_username == lblPlayer2.Text.Trim()) _nws.Write(Encoding.Default.GetBytes("|@NextRoundKing"), 0, 15); SelectCount = -1; isSelect = 0; } if (HeroN >= 8) { panSureHero.Visible = true; panHeroCards.Visible = false; SelectCount = -1; isSelect = 0; foreach (Panel i in PHC1.Controls) { i.MouseDown += PHC1_MouseDown; } } } #region 分配武将 private void PHC1_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; foreach (Panel i in SelectHeroCards) { if (p.Name == i.Name) { foreach (Panel j in panHero.Controls) { if (j.BackgroundImage == null) { j.BackgroundImage = p.BackgroundImage; p.Tag = "isSelect"; p.BackgroundImage = null; return; } } } } } private void panLhero_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; if (p.BackgroundImage == null) return; foreach (Panel i in PHC1.Controls) { if ((string)i.Tag == "isSelect") { i.BackgroundImage = p.BackgroundImage; i.Tag = null; break; } } p.BackgroundImage = null; } private void panChero_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; if (p.BackgroundImage == null) return; foreach (Panel i in PHC1.Controls) { if ((string)i.Tag == "isSelect") { i.BackgroundImage = p.BackgroundImage; i.Tag = null; break; } } p.BackgroundImage = null; } private void panRhero_MouseDown(object sender, MouseEventArgs e) { Panel p = (Panel)sender; if (p.BackgroundImage == null) return; foreach (Panel i in PHC1.Controls) { if ((string)i.Tag == "isSelect") { i.BackgroundImage = p.BackgroundImage; i.Tag = null; break; } } p.BackgroundImage = null; } #endregion private void btnHeroOK_Click(object sender, EventArgs e) { FrmSangoGame frmsangogame = new FrmSangoGame(); frmsangogame.Show() this.Hide(); } } name:5+x