小弟最近在做毕业设计,搞的就是那模拟网吧管理的一个玩意儿系统。
在客户端不进行数据库的操作,所以就需要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转载请注明出处谢谢