主要就是多线程与Socket的知识,注释写的还算详细,还是实际点帖全部代码吧。Client:using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;using System.Net;using System.Net.Sockets;
namespace TestClient{ public partial class Chat : Form { //以下是客户端到服务器端的消息开头 const string LOGININ = "10" ;//请求登陆的消息|||消息形式:10+自己的用户名 const string LOGINOUT = "11" ;//请求登出的消息|||消息形式:11+自己的用户名 const string GETULIST = "12" ;//请求获得在线用户列表|||消息形式:12+自己的用户名 const string P2PCONN = "13" ;//请求P2P连接的消息|||消息形式:13+自己的用户名+对方的用户名 const string HOLDLINE = "14";//保持连接.|||消息开式:14+自己的用户名 const string LOGINADD = "15";//新用户登录 const string LOGINREMOVE = "16";//用户登出 //以下是服务器到客户端的消息开头 const string HVUSER = "20";//用户名已存在 const string GETUSER = "21";//在线用户列表|||消息格式:21+用户名+EP const string MAKHOLD = "22";//打洞命令|||消息格式:22+IP const string LOGINOK = "23";//登陆成功 const string SERVCLS = "24";//服务器关闭 const string MSGEND = "25";//'消息结束 const string CHATMSGALL = "26";//发送给所有人 //以下是客户端到客户端的消息开头 const string HOLDOK = "30" ;//打洞成功 const string CHATMSG = "31" ;//聊天消息 const string CHTMSGEND = "32" ;//聊天消息发送成功
private string userName; public string UserName { private get { return userName; } set { userName = value; } } private IPEndPoint serverEP; public IPEndPoint ServerEP { set { serverEP = value; } private get { return serverEP; } }
Socket clientSocket; public Socket ClientSocket { private get { return clientSocket; } set { clientSocket = value; } }
int getUrecCount;
//和服务器保持连接连接时用到的byte数组 byte[] holdBytes; List<string> OLUserName; List<IPEndPoint> OLUserEP; //为保持在线状态弄得 TimerCallback timerDelegate; bool msgSendEnd = false;//消息是否发送成功,若发送成功,则会返回结束消息 private ManualResetEvent getUDone;//用来阻塞请求好友名单的线程,等待接收好友名单 private ManualResetEvent chatDone;//用来阻塞发送聊天消息时的线程 private ManualResetEvent holdDone;//用来阻塞打洞时的线程 private ManualResetEvent sendDone ;//用来阴塞发送消息的线程.等待收到回送的确认消息
//监听的线程 Thread thListen; delegate void myMethodDelegate(ref byte[] myInData);//登陆时用的事件 delegate void TextChangedMelegate(string text);//给textbox1赋值用到的委托 delegate void ComboboxBindDelegate();//用户绑定combobox的委托
static bool testHold = false; static bool testChat = false; //用户列表的数据源 DataTable dt; //上一条消息 string lastMsg = "";
public Chat() { InitializeComponent(); }
private void Chat_Load(object sender, EventArgs e) { Login login = new Login(); login.StartPosition = FormStartPosition.CenterParent; login.Tag = this; login.ShowDialog(); thListen = new Thread(new ThreadStart(this.Listen)); thListen.IsBackground = true; thListen.Start(); }
public void LoadInit() { //timerDelegate = new TimerCallback(Holdonline); //holdBytes = Encoding.Unicode.GetBytes(HOLDLINE + UserName); 登陆成功后.用一个timer,每隔50秒向服务器发送消息,保持在线状态跟在主机注册的端口 //System.Threading.Timer timer = new System.Threading.Timer(timerDelegate, null, 10000, 10000); //登陆成功后.用一个timer,每隔50秒向服务器发送消息,保持在线状态跟在主机注册的端口 System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Tick += new EventHandler(Holdonline); timer.Interval = 50000; timer.Start();
//请求在线名单 this.Text = "正在获取在线名单,请稍后...."; bool getUbool = false; //while (getUbool == false) //{ // //getUbool = GetU(); // //if (getUbool == false) // //{ // // if (MessageBox.Show("是否重试?", "是否重试", MessageBoxButtons.YesNo) == DialogResult.Yes) // // { // // getUbool = false; // // } // // else // // { // // getUbool = true; // // } // //} //} }
private bool GetU() { getUDone = new ManualResetEvent(false); byte[] getUbytes = Encoding.Unicode.GetBytes(GETULIST); ClientSocket.SendTo(getUbytes, ServerEP); byte[] data = new byte[4056]; string comStr = Encoding.Unicode.GetString(data, 0, 4); myMethodDelegate GUrecv = new myMethodDelegate(RecvGetU); GUrecv.BeginInvoke(ref data, null, null); getUDone.WaitOne(30000, true); string recvStr = Encoding.Unicode.GetString(data, 0, 4); if (recvStr == comStr) { MessageBox.Show("服务器超时.或取好友名单失败!!"); return false; } string test = Encoding.Unicode.GetString(data); if (Encoding.Unicode.GetString(data, 0, 4) == GETUSER) { GetUserList(data, getUrecCount); this.comboBox1.Invoke(new ComboboxBindDelegate(ShowUserList)); //ShowUserList(); return true; } else { MessageBox.Show("服务器未知错误,获取在线名单失败!!"); return false; } }
/// <summary> /// 显示在线用户 /// </summary> private void ShowUserList() { lock (OLUserName) { dt = new DataTable(); dt.Columns.Add("Name"); dt.Columns.Add("IP"); DataRow dr1 = dt.NewRow(); dr1["Name"] = "所有人"; dt.Rows.Add(dr1); this.comboBox1.DataSource = dt; this.comboBox1.ValueMember = "IP"; this.comboBox1.DisplayMember = "Name"; for (int i = 0; i < OLUserName.Count; i++) { if (OLUserName[i] != "") { DataRow dr = dt.NewRow(); dr["Name"] = OLUserName[i]; dr["IP"] = OLUserEP[i]; dt.Rows.Add(dr); } } } }
/// <summary> /// 处理收到的在线用户信息 /// </summary> /// <param name="userInfobytes"></param> /// <param name="reccount"></param> private void GetUserList(byte[] userInfobytes, int reccount) { string ustr = Encoding.Unicode.GetString(userInfobytes, 4, reccount - 4);
string[] splitStr = null; splitStr = ustr.Split('|'); string[] IPEPSplit = null; OLUserName = new List<string>(); OLUserEP = new List<IPEndPoint>(); int i = 0; for(int k=0;k<splitStr.Length -2;k = k+2) { OLUserName.Add(splitStr[k]); IPEPSplit = splitStr[k + 1].Split(':'); OLUserEP.Add(new IPEndPoint(IPAddress.Parse(IPEPSplit[0]), Convert.ToInt32(IPEPSplit[1]))); IPEPSplit = null; i++; } }
//用保持在线状态的函数 private void Holdonline(object state,EventArgs e) { holdBytes = Encoding.Unicode.GetBytes(HOLDLINE + UserName); ClientSocket.SendTo(holdBytes, ServerEP); }
//登陆时用来异步的接收服务器发送的消息 void RecvGetU(ref byte[] inData) { getUrecCount = ClientSocket.Receive(inData); getUDone.Set(); }
/// <summary> /// 发送 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonSend_Click(object sender, EventArgs e) { if (this.textBox2.Text.Trim() == "") return; else { SendChatMsg(this.comboBox1.Text, this.textBox2.Text); } }
/// <summary> /// 发送聊天消息 /// </summary> /// <param name="remoteUser"></param> /// <param name="chatMsgStr"></param> private void SendChatMsg(string remoteUser, string chatMsgStr) { if (lastMsg.Trim() == chatMsgStr.Trim()) { MessageBox.Show("看你傻样,还想刷屏!"); return; } else lastMsg = chatMsgStr; IPEndPoint remoteUEP = null; if (remoteUser == "所有人") { for(int i=0;i<OLUserName.Count;i++) { if (OLUserName[i].ToUpper().Trim() == this.UserName.ToUpper().Trim()) continue; byte[] msgbytes = Encoding.Unicode.GetBytes(CHATMSGALL + UserName + "|" + chatMsgStr); string test = OLUserEP[i].Address.ToString(); string port = OLUserEP[i].Port.ToString(); ClientSocket.SendTo(msgbytes, OLUserEP[i]); } this.textbox.AppendText(this.UserName + " to " + this.comboBox1.Text + ":" + chatMsgStr + "\n"); this.textbox.Focus(); Application.DoEvents(); this.textBox2.Focus(); } else { for (int i = 0; i < OLUserName.Count; i++) { if (remoteUser == OLUserName[i]) remoteUEP = OLUserEP[i]; } byte[] msgbytes = Encoding.Unicode.GetBytes(CHATMSG + userName + "|" + chatMsgStr); byte[] holdbytes = Encoding.Unicode.GetBytes(P2PCONN + userName + "|" + remoteUser); chatDone = new ManualResetEvent(false); string test = remoteUEP.Address.ToString(); string port = remoteUEP.Port.ToString(); ClientSocket.SendTo(msgbytes, remoteUEP); chatDone.WaitOne(1000, true); this.textbox.AppendText(this.UserName + " to " + this.comboBox1.Text + ":" + chatMsgStr + "\n"); //this.textbox.Focus(); Application.DoEvents(); //this.textBox2.Focus();
if (testChat) { testChat = false; return; } testHold = false; while (testHold == false) { //开始打洞 holdDone = new ManualResetEvent(false); ClientSocket.SendTo(holdbytes, remoteUEP); ClientSocket.SendTo(holdbytes, ServerEP); holdDone.WaitOne(1000, true); if (testHold == false) { //打洞超时 testHold = true; } else { //打洞成功 } } while (testChat == false) { //打洞成功准备发送 chatDone = new ManualResetEvent(false);
ClientSocket.SendTo(msgbytes, remoteUEP); chatDone.WaitOne(1000, true); if (testChat == false) { //发送超时 testChat = true; } else { //发送成功 testChat = true; } } } this.textBox2.Text = ""; testHold = false; testChat = false; }
/// <summary> /// 客户程序监听的函数 /// </summary> private void Listen() { while (true) { try { int recv = 0;//收到的字节数 byte[] data = new byte[1024];//缓冲区大小 IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint tempRemoteEP = (EndPoint)sender; recv = ClientSocket.ReceiveFrom(data, ref tempRemoteEP); //获得消息头的内容 string msgHead = Encoding.Unicode.GetString(data, 0, 4); switch (msgHead) { case MSGEND: msgSendEnd = true; sendDone.Set(); break; case LOGININ: AddOnLine(data, recv); break; case LOGINOUT: RemoveOnLine(data, recv); break; case MAKHOLD: MakeHold(data, recv); break; case CHATMSG: ShowChatMsg(data, recv); break; case CHATMSGALL: ShowChatMsgAll(data, recv); break; case HOLDOK: testHold = true; holdDone.Set(); break; case CHTMSGEND: testChat = true; chatDone.Set(); break; case LOGINADD: this.GetU(); break; case LOGINREMOVE: this.GetU(); break; } } catch { } } }
/// <summary> /// 处理聊天消息 /// </summary> /// <param name="data"></param> /// <param name="recv"></param> private void ShowChatMsgAll(byte[] data, int recv) { string msgStr = Encoding.Unicode.GetString(data, 4, recv - 4); string[] splitStr = msgStr.Split('|'); string fromUname = splitStr[0]; string msg = splitStr[1]; this.textbox.Invoke(new TextChangedMelegate(SetTextBox), fromUname + " to 所有人:" + msg); }
/// <summary> /// 处理聊天消息 /// </summary> /// <param name="data"></param> /// <param name="recv"></param> private void ShowChatMsg(byte[] data, int recv) { string msgStr = Encoding.Unicode.GetString(data, 4, recv-4); string[] splitStr = msgStr.Split('|'); string fromUname = splitStr[0]; string msg = splitStr[1]; this.textbox.Invoke(new TextChangedMelegate(SetTextBox), fromUname + " to " + userName + ":" + msg); //this.textBox1.Text += fromUname + " to " + userName + ":" + msg + "\n"; byte[] tempbytes = Encoding.Unicode.GetBytes(CHTMSGEND); for (int i = 0; i < OLUserName.Count; i++) { if (OLUserName[i].ToUpper() == fromUname.ToUpper()) { ClientSocket.SendTo(tempbytes, OLUserEP[i]); } } }
private void SetTextBox(string text) { this.textbox.SelectionColor = Color.Blue; this.textbox.AppendText(text + "\n"); //this.textbox.Focus(); Application.DoEvents(); //this.textBox2.Focus(); }
/// <summary> /// 处理打洞函数 /// </summary> /// <param name="data"></param> /// <param name="recv"></param> private void MakeHold(byte[] indata, int recvcount) { string makholdstr = Encoding.Unicode.GetString(indata, 4, recvcount); string[] ipepstr = makholdstr.Split(':'); IPEndPoint holdEP = new IPEndPoint(IPAddress.Parse(ipepstr[0]), Convert.ToInt32(ipepstr[1])); byte[] holdbytes = Encoding.Unicode.GetBytes(HOLDOK + UserName); //回送打洞消息 ClientSocket.SendTo(holdbytes, holdEP); }
/// <summary> /// 处理用户上线的函数 /// </summary> private void AddOnLine(byte[] inData, int recvCount) { string inStr = Encoding.Unicode.GetString(inData, 4, recvCount - 4); string[] userinfo = inStr.Split('|'); string[] strUserEP = userinfo[1].Split(':'); int count = OLUserName.Count - 1; //for (int i = 0; i < count; i++) //{ // if (OLUserName[i] == "") // { OLUserName.Add(userinfo[0]); IPEndPoint ip = new IPEndPoint(IPAddress.Parse(strUserEP[0]), Convert.ToInt32(strUserEP[1])); OLUserEP.Add(ip); lock (dt) { DataRow dr = this.dt.NewRow(); dr["Name"] = userinfo[0]; dr["IP"] = ip; dt.Rows.Add(dr); } this.textbox.Invoke(new TextChangedMelegate(SetTextBox), userinfo[0] + "上线了!"); //this.textBox1.Text += userinfo[0] + "上线了!\n"; //break; // } //} }
/// <summary> /// 处理用户下线的函数 /// </summary> private void RemoveOnLine(byte[] inData,int recvCount) { string offUname = Encoding.Unicode.GetString(inData,4,recvCount-4); for(int i = 0; i< OLUserName.Count-1;i++) { if(OLUserName[i] == offUname) { OLUserName.Remove(offUname); OLUserEP.RemoveAt(i); lock (dt) { foreach (DataRow dr in dt.Rows) { if (dr["name"].ToString().Trim() == offUname.Trim()) { dt.Rows.Remove(dr); break; } } } this.textbox.Invoke(new TextChangedMelegate(SetTextBox), offUname + "下线了!"); //this.textBox1.Text += offUname + "下线了!\n"; break; } } }
private void textBox2_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '\r') this.buttonSend_Click(null, null); }
private void textbox_TextChanged(object sender, EventArgs e) { 让文本框获取焦点 //this.textbox.Focus(); 设置光标的位置到文本尾 //this.textbox.Select(this.richTextBoxInfo.TextLength, 0); 滚动到控件光标处 //this.textbox.ScrollToCaret(); }
private void Chat_FormClosed(object sender, FormClosedEventArgs e) { this.thListen.Abort(); string loginOutStr = LOGINOUT + UserName; byte[] sendBytes = Encoding.Unicode.GetBytes(loginOutStr); ClientSocket.SendTo(sendBytes,ServerEP); } }}namespace TestClient{ partial class Chat { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null;
/// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); }
#region Windows 窗体设计器生成的代码
/// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void InitializeComponent() { this.panel1 = new System.Windows.Forms.Panel(); this.buttonSend = new System.Windows.Forms.Button(); this.textBox2 = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.comboBox1 = new System.Windows.Forms.ComboBox(); this.textbox = new System.Windows.Forms.RichTextBox(); this.panel1.SuspendLayout(); this.SuspendLayout(); // // panel1 // this.panel1.Controls.Add(this.buttonSend); this.panel1.Controls.Add(this.textBox2); this.panel1.Controls.Add(this.label1); this.panel1.Controls.Add(this.comboBox1); this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; this.panel1.Location = new System.Drawing.Point(0, 382); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(557, 59); this.panel1.TabIndex = 0; // // buttonSend // this.buttonSend.Location = new System.Drawing.Point(470, 29); this.buttonSend.Name = "buttonSend"; this.buttonSend.Size = new System.Drawing.Size(75, 23); this.buttonSend.TabIndex = 1; this.buttonSend.Text = "发送"; this.buttonSend.UseVisualStyleBackColor = true; this.buttonSend.Click += new System.EventHandler(this.buttonSend_Click); // // textBox2 // this.textBox2.Location = new System.Drawing.Point(3, 29); this.textBox2.Name = "textBox2"; this.textBox2.Size = new System.Drawing.Size(443, 21); this.textBox2.TabIndex = 0; this.textBox2.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox2_KeyPress); // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(3, 6); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(53, 12); this.label1.TabIndex = 2; this.label1.Text = "发送给:"; // // comboBox1 // this.comboBox1.FormattingEnabled = true; this.comboBox1.Location = new System.Drawing.Point(62, 3); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(121, 20); this.comboBox1.TabIndex = 3; // // textbox // this.textbox.BackColor = System.Drawing.SystemColors.ActiveCaptionText; this.textbox.Dock = System.Windows.Forms.DockStyle.Fill; this.textbox.Location = new System.Drawing.Point(0, 0); this.textbox.Name = "textbox"; this.textbox.ReadOnly = true; this.textbox.Size = new System.Drawing.Size(557, 382); this.textbox.TabIndex = 1; this.textbox.Text = ""; this.textbox.TextChanged += new System.EventHandler(this.textbox_TextChanged); // // Chat // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(557, 441); this.Controls.Add(this.textbox); this.Controls.Add(this.panel1); this.Name = "Chat"; this.Text = "Chat"; this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Chat_FormClosed); this.Load += new System.EventHandler(this.Chat_Load); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1; private System.Windows.Forms.TextBox textBox2; private System.Windows.Forms.Label label1; private System.Windows.Forms.ComboBox comboBox1; private System.Windows.Forms.Button buttonSend; private System.Windows.Forms.RichTextBox textbox; }}using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Net;using System.Net.Sockets;using System.Threading;
namespace TestClient{ public partial class Login : Form { //以下是客户端到服务器端的消息开头 const string LOGININ = "10";//请求登陆的消息|||消息形式:10+自己的用户名 const string LOGINOK = "23";//登陆成功 //以下是服务器到客户端的消息开头 const string HVUSER = "20";//用户名已存在
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //客户端套节字的定义 IPEndPoint serverEP;//服务器的IPEP
delegate void myMethodDelegate(ref byte[] myInData);//登陆时用的事件
private ManualResetEvent receiveDone;//在登陆时用来阻塞线程,等待收到数据
bool inPutOk = false; public Login() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { try { serverEP = new IPEndPoint(IPAddress.Parse(this.textBoxServerIP.Text), 11000); inPutOk = true; } catch { MessageBox.Show("你输入的服务器IP不正确,请重新输入."); inPutOk = false; }
//判断用户是否登陆成功 bool ok = false; while (ok == false) { bool loginOk = LogOn(this.textBoxUserName.Text); if (loginOk) ok = true; else { DialogResult res = MessageBox.Show("是否重试?", "是否重试", MessageBoxButtons.YesNo); if (res == DialogResult.No) ok = true; else ok = false; } } Chat c = (Chat)this.Tag; c.UserName = this.textBoxUserName.Text; c.ServerEP = serverEP; c.ClientSocket = clientSocket; c.LoadInit(); this.Close(); }
//登陆函数 private bool LogOn(string username) { receiveDone = new ManualResetEvent(false); byte[] userBytes = null; bool userOk = false; //判断用户名是否符合格式 while(userOk != true) { username = username.ToUpper(); userBytes = Encoding.Unicode.GetBytes(LOGININ + username);
if(userBytes.Length > 24 || userBytes.Length < 10) { MessageBox.Show("用户名不得小于6个字节,且不得大于20个字节."); return false; } else userOk = true; }
//向服务器发送客户消息 clientSocket.SendTo(userBytes, serverEP); byte[] data = new Byte[1024]; string comStr = Encoding.Unicode.GetString(data,0,4);
//异面的接收服务器回送的消息 myMethodDelegate DGrecv = new myMethodDelegate(RecvLogin); DGrecv.BeginInvoke(ref data, null, null);
//等待服务器回送消息的时长为10秒,否则为服务器超时 receiveDone.WaitOne(30000, true);
string recvStr = Encoding.Unicode.GetString(data,0,4); if(recvStr == comStr) { MessageBox.Show("服务器超时.登陆失败!!"); return false; } else { if(Encoding.Unicode.GetString(data,0,4) == LOGINOK) { MessageBox.Show("登陆成功!!"); } else { if (Encoding.Unicode.GetString(data, 0, 4) == HVUSER) { MessageBox.Show("用户名重复.登陆失败!!"); return false; } else { if (Encoding.Unicode.GetString(data, 0, 4) == LOGINOK) { MessageBox.Show("服务器未知错误,登陆失败!!!!"); return false; } } } } return true; }
//登陆时用来异步的接收服务器发送的消息 void RecvLogin(ref byte[] inData) { clientSocket.Receive(inData); receiveDone.Set(); } }}namespace TestClient{ partial class Login { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null;
/// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); }
#region Windows 窗体设计器生成的代码
/// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void InitializeComponent() { this.label2 = new System.Windows.Forms.Label(); this.textBoxServerIP = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.textBoxUserName = new System.Windows.Forms.TextBox(); this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(56, 27); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(77, 12); this.label2.TabIndex = 7; this.label2.Text = "服务器IP:"; // // textBoxServerIP // this.textBoxServerIP.Location = new System.Drawing.Point(139, 24); this.textBoxServerIP.Name = "textBoxServerIP"; this.textBoxServerIP.Size = new System.Drawing.Size(100, 21); this.textBoxServerIP.TabIndex = 6; this.textBoxServerIP.Text = "10.24.11.231"; // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(56, 68); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(53, 12); this.label1.TabIndex = 9; this.label1.Text = "用户名:"; // // textBoxUserName // this.textBoxUserName.Location = new System.Drawing.Point(139, 65); this.textBoxUserName.Name = "textBoxUserName"; this.textBoxUserName.Size = new System.Drawing.Size(100, 21); this.textBoxUserName.TabIndex = 8; // // button1 // this.button1.Location = new System.Drawing.Point(100, 106); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 10; this.button1.Text = "登 陆"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // Login // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 144); this.Controls.Add(this.button1); this.Controls.Add(this.label1); this.Controls.Add(this.textBoxUserName); this.Controls.Add(this.label2); this.Controls.Add(this.textBoxServerIP); this.Name = "Login"; this.Text = "Login"; this.ResumeLayout(false); this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox textBoxServerIP; private System.Windows.Forms.Label label1; private System.Windows.Forms.TextBox textBoxUserName; private System.Windows.Forms.Button button1; }}Server:using System;using System.Drawing;using System.Collections;using System.Collections.Generic;using System.ComponentModel;using System.Windows.Forms;using System.Data;using System.Net.Sockets;using System.Threading;using System.Net;using System.Text;
namespace ChatServer{ /// <summary> /// Form1 的摘要说明。 /// </summary> public partial class Form1 : System.Windows.Forms.Form { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.Container components = null; //全局变量 Socket ServerSocket = null; IPEndPoint ipep = null; Hashtable htUserList = null; string[] userName = new string[1000]; IPEndPoint[] userIPEP = new IPEndPoint[1000]; int[] userTime = new int[1000]; TimerCallback timerDelegate = null; WriteLog writeLog = null; Thread listenTH = null; bool flag = true;
//常量 //以下是客户端到服务器端的消息开头 const string LOGININ = "10"; //请求登陆的消息|||消息形式:10+自己的用户名 const string LOGINOUT = "11"; //请求登出的消息|||消息形式:11+自己的用户名 const string GETULIST = "12"; //请求获得在线用户列表|||消息形式:12 const string P2PCONN = "13"; //请求P2P连接的消息|||消息形式:13+自己的用户名+|+对方的用户名 const string HOLDLINE = "14"; //保持连接.|||消息开式:14+自己的用户名 const string LOGINADD = "15";//新用户登录 const string LOGINREMOVE = "16";//用户登出
//以下是服务器到客户端的消息开头 const string HVUSER = "20"; //用户名已存在 const string GETUSER = "21"; //在线用户列表|||消息格式:21+用户名+EP const string MAKHOLD = "22"; //打洞命令|||消息格式:22+IP const string LOGINOK = "23"; //登陆成功 const string SERVCLS = "24"; //服务器关闭 const string MSGEND = "25"; //消息结束
//以下是服务器端的命名 const string EXITPRO = "EXIT"; //退出命令 const string SHOWULIST = "SHOWUSER"; private System.Windows.Forms.StatusBar statusBar1; private System.Windows.Forms.StatusBarPanel statusBarPanel1; private System.Windows.Forms.TextBox textBox1; //显示在线用户 const string HELP = "HELP"; //显示帮助 private List<IPEndPoint> onlineIPList;
public Form1() { // // Windows 窗体设计器支持所必需的 // InitializeComponent();
//初始化变量 ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); ipep = new IPEndPoint(IPAddress.Any, 11000); htUserList = new Hashtable(); writeLog = new WriteLog(); timerDelegate = new TimerCallback(OnLineTimeOut); }
/// <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.statusBar1 = new System.Windows.Forms.StatusBar(); this.statusBarPanel1 = new System.Windows.Forms.StatusBarPanel(); this.textBox1 = new System.Windows.Forms.TextBox(); ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).BeginInit(); this.SuspendLayout(); // // statusBar1 // this.statusBar1.Location = new System.Drawing.Point(0, 319); this.statusBar1.Name = "statusBar1"; this.statusBar1.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] { this.statusBarPanel1}); this.statusBar1.ShowPanels = true; this.statusBar1.Size = new System.Drawing.Size(466, 22); this.statusBar1.TabIndex = 0; // // statusBarPanel1 // this.statusBarPanel1.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Spring; this.statusBarPanel1.Text = "statusBarPanel1"; this.statusBarPanel1.Width = 450; // // textBox1 // this.textBox1.Dock = System.Windows.Forms.DockStyle.Left; this.textBox1.Location = new System.Drawing.Point(0, 0); this.textBox1.Multiline = true; this.textBox1.Name = "textBox1"; this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.textBox1.Size = new System.Drawing.Size(286, 319); this.textBox1.TabIndex = 1; this.textBox1.Text = ""; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(6, 14); this.ClientSize = new System.Drawing.Size(466, 341); this.Controls.Add(this.textBox1); this.Controls.Add(this.statusBar1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.Name = "Form1"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "服务程序"; this.Load += new System.EventHandler(this.Form1_Load); this.Closed += new System.EventHandler(this.Form1_Closed); ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).EndInit(); this.ResumeLayout(false);
} #endregion
/// <summary> /// 启动服务器 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, System.EventArgs e) { IPAddress[] addressList = Dns.GetHostByName(Dns.GetHostName()).AddressList; IPAddress ServerIP = addressList[0]; ServerSocket.Bind(ipep); SetStatusText("服务器正在启动......"); SetStatusText("服务器IP:" + ServerIP.ToString() + " 正在监听" + ipep.Port.ToString() + "端口"); listenTH = new Thread(new ThreadStart(Listen)); //监听线程 listenTH.Start(); //启动 SetStatusText("服务器启动成功....."); System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Tick += new EventHandler(timer_Tick); timer.Interval = 5000; timer.Start(); }
/// <summary> /// 服务器监听函数 /// </summary> private void Listen() { try { while (flag) { int recv = 0; byte[] data = new byte[1024]; IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint tempRemoteEP = sender as EndPoint; recv = ServerSocket.ReceiveFrom(data, ref tempRemoteEP); string msgHead = Encoding.Unicode.GetString(data, 0, 4); switch (msgHead) { case LOGININ: //用户登录 string LoginThing = UserLogin(data, (IPEndPoint)tempRemoteEP, recv); if (LoginThing == HVUSER) //用户存在 { SendMsg(HVUSER, (IPEndPoint)tempRemoteEP); } else { SendMsg(LOGINOK, (IPEndPoint)tempRemoteEP); if (onlineIPList == null) { onlineIPList = new List<IPEndPoint>(); } onlineIPList.Add((IPEndPoint)tempRemoteEP); foreach (IPEndPoint ip in onlineIPList) { SendMsg(LOGINADD, ip); } } break; case LOGINOUT: //用户退出 Userloginout(data, recv); onlineIPList.Remove((IPEndPoint)tempRemoteEP); foreach (IPEndPoint ip in onlineIPList) { SendMsg(LOGINREMOVE, ip); } break; case GETULIST: // 获取用户列表 string userInfor = GetUserList(); SendMsg(GETUSER + userInfor, (IPEndPoint)tempRemoteEP); break; case P2PCONN: //打洞 QuestP2PConn(data, recv); break; case HOLDLINE: HoldOnLine(data, recv); break; } } } catch (System.Exception errr) { writeLog.AppendErrorLog(errr.ToString()); } }
/// <summary> /// 保持用户在线 /// </summary> /// <param name="data"></param> /// <param name="recvCount"></param> private void HoldOnLine(byte[] data, int recvCount) { string Uname = Encoding.Unicode.GetString(data, 4, recvCount - 4); int i = 0; for (i=0;i<userName.Length;i++) { if (Uname == userName[i]) { userTime[i] = 60; break; } } }
/// <summary> /// 用户超时退出 /// </summary> private void OnLineTimeOut(object state) { int i = 0, j= 0; for (i=0;i<userName.Length;i++) { if (userTime[i] > 0) { userTime[i] -= 5; if (userTime[i] < 0) { string loginoutmsg = LOGINOUT + userName[i]; userName[i] = ""; userIPEP[i] = null; byte[] ULoginOutbytes = Encoding.Unicode.GetBytes(loginoutmsg); for (i=1;j<userName.Length;j++) { if (userName[j] != "") { if (userIPEP[j] != null) { ServerSocket.SendTo(ULoginOutbytes, userIPEP[j]); } } } } } } }
/// <summary> /// 转发P2P连接请求 /// </summary> private void QuestP2PConn(byte[] data, int recv) { string recvStr = Encoding.Unicode.GetString(data, 4, recv - 4); string[] split = recvStr.Split(new char[]{'|'}); IPEndPoint fromEP = null, toEP = null; int i; for (i=0;i<userName.Length;i++) { if (userName[i] == split[0]) { fromEP = userIPEP[i]; } if (userName[i] == split[1]) { toEP = userIPEP[i]; } } byte[] holdbyte = Encoding.Unicode.GetBytes(MAKHOLD + fromEP.ToString()); ServerSocket.SendTo(holdbyte, toEP); }
/// <summary> /// 用户登录,直接返回登陆是否成功的值 /// </summary> /// <param name="data"></param> /// <param name="userEP"></param> /// <param name="recvCount"></param> /// <returns></returns> private string UserLogin(byte[] data, IPEndPoint userEP, int recvCount) { string Uname = Encoding.Unicode.GetString(data, 4, recvCount - 4); byte[] Uinfobytes = null; int i, j; for (i=0;i<userName.Length;i++) { if (userName[i] != "" && userName[i] != null) { if (userName[i].Equals(Uname)) return HVUSER; } } for (i=0;i<userName.Length;i++) { if (userName[i] == "" || userName[i] == null) { userName[i] = Uname; userIPEP[i] = userEP; userTime[i] = 60; Uinfobytes = Encoding.Unicode.GetBytes(LOGININ + userName[i] + "|" + userIPEP[i].ToString()); for (j=1;j<userName.Length;j++) { if (userName[j] != "" && userName[j] != Uname && userName[j] != null && userIPEP[j] != null) { ServerSocket.SendTo(Uinfobytes, userIPEP[j]); } } break; } } return LOGINOK; }
/// <summary> /// 用户退出 /// </summary> /// <param name="data"></param> /// <param name="recvCount"></param> private void Userloginout(byte[] data, int recvCount) { int i = 0, j = 0; string Uname = Encoding.Unicode.GetString(data, 4, recvCount - 4); for (i=0;i<userName.Length;i++) { if (Uname.ToUpper() == userName[i].ToUpper()) { string loginOutMsg = LOGINOUT + Uname; userName[i] = ""; userIPEP[i] = null; userTime[i] = 0; for (j=1;j<userName.Length;j++) { if (userName[j]!= null && userName[j] != "") { SendMsg(loginOutMsg, userIPEP[j]); } } break; } } }
/// <summary> /// 获取用户列表 /// </summary> /// <returns></returns> private string GetUserList() { string userInfor = ""; int i = 0; for (i=0;i<userName.Length;i++) { if (userName[i] != "" && userName[i] != null && userIPEP[i] != null) { userInfor += userName[i] + "|" + userIPEP[i].ToString() + "|"; } } return userInfor; }
/// <summary> /// 发送消息 /// </summary> /// <param name="msg"></param> /// <param name="remoteEP"></param> private void SendMsg(string msg, IPEndPoint remoteEP) { byte[] sendBytes = Encoding.Unicode.GetBytes(msg); try { ServerSocket.SendTo(sendBytes, remoteEP); } catch (System.Exception errr) { writeLog.AppendErrorLog(errr.ToString()); } }
/// <summary> /// 提示信息 /// </summary> /// <param name="text"></param> /// <returns></returns> private void SetStatusText(string text) { this.statusBarPanel1.Text = text; }
/// <summary> /// 显示在线用户 /// </summary> private StringBuilder ShowUser() { StringBuilder strB = new StringBuilder(); if (userName != null && userName.Length > 0) { int i; for (i=0;i<userName.Length;i++) { if (userName[i] != "" && userIPEP[i] != null) { strB.Append(Environment.NewLine + "用户名:" + userName[i] + " 地址:" + userIPEP[i].ToString()); } } } return strB; }
/// <summary> /// 退出 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Closed(object sender, System.EventArgs e) { flag = false; if (listenTH != null) { if (listenTH.ThreadState == ThreadState.Running) { listenTH.Abort(); } listenTH = null; } timerDelegate = null; ServerSocket.Close(); }
private void timer_Tick(object sender, EventArgs e) { OnLineTimeOut(null); StringBuilder strB = ShowUser(); this.textBox1.Text = strB.ToString(); }
}}using System;using System.Text;using System.IO;using System.Windows.Forms;
namespace ChatServer{ /// <summary> /// WriteLog 的摘要说明。 /// </summary> public class WriteLog { public WriteLog() { // // TODO: 在此处添加构造函数逻辑 // } /// <summary> /// 追加日志文件 /// </summary> /// <param name="errorMsg"></param> public void AppendErrorLog(string errorMsg) { try { StringBuilder strB = new StringBuilder(); strB.Append(DateTime.Now.ToString()); strB.Append(" "); strB.Append(Environment.MachineName.ToString()); strB.Append(" "); strB.Append(Environment.UserDomainName.ToString() + "\\" + Environment.UserName); strB.Append(" "); strB.Append(Environment.OSVersion.Platform.ToString() + "\\" + Environment.OSVersion.Version.ToString()); strB.Append(Environment.NewLine + Environment.NewLine); strB.Append(errorMsg); strB.Append(Environment.NewLine + Environment.NewLine); AppendErrorLog(strB); } catch{} }
/// <summary> /// 追加日志文件 /// </summary> /// <param name="strB"></param> public void AppendErrorLog(StringBuilder strB) { try { string filePath = ""; filePath = CreateErrorLogFile(); FileStream fileStream = File.Open(filePath, FileMode.Append, FileAccess.Write); StreamWriter streamWriter = new StreamWriter(fileStream); streamWriter.Write(strB.ToString()); streamWriter.Flush(); streamWriter.Close(); fileStream.Close(); fileStream = null; } catch{} }
/// <summary> /// 创建日志文件 /// </summary> private string CreateErrorLogFile() { string directoryPath = Application.StartupPath + "\\ErrorLog"; string filePath = string.Empty; //判断日志文件夹是否存在 if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } //根据日期创建日志文件 filePath = directoryPath + "\\Error" + string.Format("{0:D2}", DateTime.Today.Year) + string.Format("{0:D2}", DateTime.Today.Month) + string.Format("{0:D2}", DateTime.Today.Day) + ".log"; if (!File.Exists(filePath)) { FileStream fileStream = File.Create(filePath); fileStream.Close(); } return filePath; }
}}
posted on 2007-04-04 10:54 tianyamoon 阅读( ...) 评论( ...) 编辑 收藏
转载于:https://www.cnblogs.com/tianyamoon/archive/2007/04/04/699414.html