小弟最近在做毕业设计,搞的就是那模拟网吧管理的一个玩意儿系统。
在客户端不进行数据库的操作,所以就需要tcp去通信来联系了。
网上搜索的东西零零碎碎,也不齐全,小弟用了好久终于整理好的一套齐全的TCP通信模板,忍不住想贴出来共享共享咯。
这里先讲客户端,下一篇就讲服务器端咯。
下面这个类的对象就是在通信过程中发送的东西。
因为对网上发送字符串,用分号隔开的做法感到很不爽。发送对象就方便操作多了。(类里面的东西太多了,都发送过去的话...无限YY中哇)
其实也就是在发送的时候进行序列化,接收的时候进行反序列化。
namespace commands { //注意这行,序列化用的 [Serializable] public class MessageInfo { public commands.CommandsTypes CommandsTypes { get; set; } public string MessageContent { get; set; } public string NameForm { get; set; } public string Password { get; set; } public string NameTo { get; set; } } }
下面就是我那CommandsTypes 的枚举。
Request前缀就是对服务器发送的请求,Res前缀的就是服务器返回来的回应
namespace commands { public enum CommandsTypes { /// <summary> /// 机器连接 /// </summary> RequestMachineLogin, ResMachineLogin, RequestLogout, /// <summary> /// 发送信息给别人 /// </summary> RequestTalk, /// <summary> /// 修改密码 /// </summary> RequestModPWD, /// <summary> /// 修改密码 /// </summary> ResModPWD, /// <summary> /// 用户登录 /// </summary> RequestUserLogin, /// <summary> /// 用户登陆 /// </summary> ResUserLogin, /// <summary> /// 用户登出 /// </summary> RequestUserlogout, /// <summary> /// 用户登出 /// </summary> ResUserlogout, /// <summary> ///用了多久 /// </summary> RequestHowLong, /// <summary> ///用了多久 /// </summary> ResHowLong, /// <summary> /// 换机子 /// </summary> RequestChangeComputer, /// <summary> /// 换机子 /// </summary> ResChangeComputer, } }
有了这两个,就可以进入正题鸟哇。
这是我添加的引用,至于哪个空间干嘛的大家就自个去捋顺吧
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.Remoting; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Windows.Forms; using System.Diagnostics; using System.Configuration; using commands;
下面就是主题鸟,通信的东西全在里面
IPAddress localAddress; private bool isExit = false; private TcpClient client; private BinaryReader br; private BinaryWriter bw; //是否已经连接服务器,用于用户登录 private bool isMechineLogined=false; private static string clientUserName; /// <summary> /// 发送消息的一个例子:用户登录,在服务器验证账号密码,我那项目里面还有很多,放出来浪费大家时间了 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_OK_Click(object sender, EventArgs e) { if (isMechineLogined) { MessageInfo obj_login = new MessageInfo(); obj_login.CommandsTypes = CommandsTypes.RequestUserLogin; obj_login.NameForm = UsernameTextBox.Text; obj_login.Password = PasswordTextBox.Text; SendMessage(obj_login); } else { MessageBox.Show("服务器连接失败!"); if (!isMechineLogined) { ConnectServer(); } } } private void FrmLogin_Load(object sender, EventArgs e) { if (!isMechineLogined) { ConnectServer(); } } /// <summary> /// 连接服务器 /// </summary> public void ConnectServer() { //buttonConnect.Enabled = false; try { //服务器ip,这里暂时放在配置文件里面 string ipaddress = System.Configuration.ConfigurationManager.AppSettings["IPAddress"]; client = new TcpClient(ipaddress, 51888); label_connectStatus.Text = "已连接服务器"; isMechineLogined = true; } catch (Exception) { label_connectStatus.Text = "连接失败"; isMechineLogined = false; return; } //这个方法到这里为止,连接就完成了,下面的就和收消息与发消息有关了 NetworkStream networkstream = client.GetStream(); br = new BinaryReader(networkstream); bw = new BinaryWriter(networkstream); MessageInfo userSend = new MessageInfo(); userSend.CommandsTypes = CommandsTypes.RequestMachineLogin; SendMessage(userSend); //创建收消息的线程 Thread threadRecive = new Thread(new ThreadStart(ReceiveData)); threadRecive.IsBackground = true; threadRecive.Start(); } /// <summary> /// 处理从服务器收到的信息 /// </summary> private void ReceiveData() { MessageInfo pc; while (isExit == false) { try { //使用缓冲 byte[] bytes = new byte[999]; int i = br.Read(bytes, 0, 999); MemoryStream memory = new MemoryStream(bytes); BinaryFormatter format = new BinaryFormatter(); pc = (MessageInfo)format.Deserialize(memory); } catch (Exception) { if (isExit == false) { MessageBox.Show("网络连接中断!"); isMechineLogined = false; ShowMain(); } break; } //处理从服务器收到的信息 switch (pc.CommandsTypes) { case CommandsTypes.ResUserLogin: //规定服务器那边验证账号密码成功就把MessageContent=="true",否则就是失败原因 if (pc.MessageContent=="true") { //登录成功 //MessageBox.Show("登录成功"); HideMain(); clientUserName= pc.NameTo; } else { //登录失败 MessageBox.Show("登录失败:"+pc.MessageContent); } break; case CommandsTypes.ResHowLong: MessageBox.Show(pc.MessageContent); break; case CommandsTypes.ResUserlogout: if (pc.MessageContent == "true") { //下机成功 ShowMain(); //MessageBox.Show("下机成功"); } else { //下机失败 MessageBox.Show("下机失败"); } break; case CommandsTypes.RequestTalk: MessageBox.Show(pc.MessageContent); break; case CommandsTypes.ResModPWD: MessageBox.Show(pc.MessageContent); break; default: break; } } } /// <summary> /// 向服务器发送信息 /// </summary> /// <param name="message"></param> private void SendMessage(MessageInfo sendObject) { MemoryStream memory = new MemoryStream(); BinaryFormatter format = new BinaryFormatter(); format.Serialize(memory, sendObject); byte[] bytes = memory.ToArray(); try { bw.Write(bytes); bw.Flush(); } catch (Exception) { //MessageBox.Show("发送失败!"); } } /// <summary> /// 线程委托,这里面有一个递归 ///我用来隐藏主界面和显示系统托盘的图标的 /// </summary> /// <param name="str"></param> private delegate void HideMainDelegate(); private void HideMain() { //子线程调用 if (this.InvokeRequired) { HideMainDelegate d = HideMain; this.Invoke(d); } //创建控件的父线程调用 else { notifyIcon_Main.Visible = true; this.Visible = false; } } private delegate void ShowMainDelegate(); private void ShowMain() { //子线程调用 if (this.InvokeRequired) { ShowMainDelegate d = ShowMain; this.Invoke(d); } //父线程调用 else { kboardhook.KeyMaskStart(); notifyIcon_Main.Visible = false; this.Visible = true; } }
好鸟,客户端一些主要的方法就放出来鸟。
敬请期待下一篇博文,服务器端篇。
ps转载请注明出处谢谢