📄 formmain.cs
字号:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using IMLibrary;
using System.Security.Cryptography;
namespace LanMsg
{
public sealed partial class FormMain : DevComponents.DotNetBar.Office2007RibbonForm //Form
{
#region Main函数
public FormMain()
{
InitializeComponent();
this.Left = Screen.PrimaryScreen.WorkingArea.Width - this.Width;
this.Top = 200;
this.loginIcon = (System.Drawing.Icon) FormAccess.resourceManager.GetObject("community1");
LanMsg.FormAccess.formMain = this;
FormAccess.sockUDP = this.sockUDP1;
}
#endregion
#region 用户变量申明区
/// <summary>
///
/// </summary>
FormHide fHide = new FormHide();
/// <summary>
/// 确定当用户是否退出应用程序
/// </summary>
private bool isExitApp = false;//确定当用户是否退出应用程序
/// <summary>
/// 记录当前用户是否设置自动登录
/// </summary>
private bool selfAutoLogin = false;
/// <summary>
/// 登录图标
/// </summary>
private System.Drawing.Icon loginIcon;
#endregion
#region FormMain_Load事件
private void FormMain_Load(object sender, EventArgs e)
{
///初始化表情
for (int i = 0; i < 195; i++)
FormAccess.formMain.imageListFace.Images.Add(i.ToString(), (System.Drawing.Image)FormAccess.resourceManager.GetObject("_" + i.ToString()));
this.fHide.Show();//将显示隐藏窗口,用于关闭或重新启动计算机时退出程序
this.Hide();
BeginListen();//选择服务端口并开始侦听服务
readyLogin(true );
FormAccess.selfInfo.userNameChanged +=new UserInfo.userNameChangedEventHandler(selfInfo_userNameChanged);
FormAccess.selfInfo.userStateChanged += new UserInfo.userStateChangedEventHandler(selfInfo_userNameChanged);
this.tabSelfInfo.TextChanged += new EventHandler(tabSelfInfo_TextChanged);
}
private void tabSelfInfo_TextChanged(object sender, EventArgs e)
{
this.NotifyIcon.Text = tabSelfInfo.Text;
}
private void selfInfo_userNameChanged(object sender)
{
IMLibrary.UserInfo user =sender as IMLibrary.UserInfo;
this.tabSelfInfo.Text = user.userName + user.StateInfo;
this.tabSelfInfo.Refresh();
}
#endregion
#region 窗口启动时准备登录readyLogin()
/// <summary>
/// 窗口启动时准备登录
/// </summary>
/// <param name="IsFirstLogin">是否首次登录</param>
private void readyLogin(bool IsFirstLogin)
{
if (FormAccess.selfInfo.State == 0)//输入用户与密码
{
FormLogin f = new FormLogin();
if (!IsFirstLogin)
{
f.checkBoxAoutLogin.Checked = false;
f.Update1.Dispose();
}
f.ShowDialog();
if (f.isExitApp)
{
f.Dispose();
this.ExitApp();
}
FormAccess.selfInfo.UserID = f.textUserID.Text.Trim();
FormAccess.selfPassword = f.textPassword.Text;
this.selfAutoLogin = f.checkBoxAoutLogin.Checked;
f.Dispose();
FormAccess.dbDepToDeps();//将数据库中组织机构表加载到Deps集合
FormAccess.dbUserToUsers();//将数据库中用户表加载到Users集合
if (LanMsg.dataAccess.IsCorrectPassword(FormAccess.selfInfo.UserID, FormAccess.selfPassword))//如果密码正确,则用户可以加载基础数据
{
FormAccess.usersToTreeView(this.TreeUsers);//将用户表填充至TreeView控件
FormAccess.depsToTreeView(this.TreeUsers);//将组织机构填充至TreeView控件
this.NotifyIcon.ContextMenuStrip = this.contextMenuNotify;
}
this.Login();//开始登录
this.timerLogin.Enabled = true; //开始检测登录
}
}
#endregion
#region 应用退出程序函数 ExitApp()
/// <summary>
/// 应用退出程序函数
/// </summary>
public void ExitApp()
{
////////告诉服务器,自己已经离线
byte[] buffer = new byte[1];
buffer[0] = 0;
IMLibrary.ServerMsg msg = new IMLibrary.ServerMsg(FormAccess.selfInfo.ID, buffer);
FormAccess.sendMsgToServer(2, msg);
//////////告诉其它用户自己已经离线
FormAccess.sendMsgToAllUser(12, IMLibrary.TextEncoder.textToBytes(FormAccess.selfInfo.UserID));
///
this.NotifyIcon.Dispose();
System.Threading.Thread.Sleep(100);
this.sockUDP1.CloseSock();
System.Threading.Thread.Sleep(100);
this.isExitApp = true;
System.Diagnostics.Process.GetCurrentProcess().Kill();//强制杀进程结束程序
try
{ Application.Exit(); }
catch { }
}
#endregion
#region 数据到达事件
private void sockUDP1_DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
{
DataArrivaldelegate outdelegate = new DataArrivaldelegate(DataArrival);
this.BeginInvoke(outdelegate, new object[] { Data, Ip, Port });
}
#endregion
#region 选择服务端口并开始侦听服务BeginListen()
/// <summary>
/// 选择服务端口并开始侦听服务
/// </summary>
private void BeginListen()
{
System.Random i = new Random();
resetPort:
int j = i.Next(2000, 60000);//端口取值范围
try
{
this.sockUDP1.Listen(j);//UDP开始侦听来自外部的消息
}
catch
{
goto resetPort;
}
System.Net.IPAddress[] ip = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName());//获得本机局域网地址
FormAccess.selfInfo.IP = ip[ip.Length-1];//获得本机局域网地址
FormAccess.selfInfo.Port = j;//获得本机局域网端口
FormAccess.LocalIp = ip[ip.Length - 1];//获得本机局域网地址
FormAccess.LocalPort = j;//获得本机局域网端口
//System.Net.IPAddress[] ipServer = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName());//获得服务器IP地址
//FormAccess.ServerIP = ipServer[0];//获得服务器IP地址
}
#endregion
#region 数据达到事件处理过程DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
private delegate void DataArrivaldelegate(byte[] Data, System.Net.IPAddress Ip, int Port);
private void DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)
{
int cnt = 0;//记录接收到的数据包大小
cnt = Data.Length;//获取接收到的数据包大小
if (cnt < 3) return;//如果收到的数据小于3个字节则视为非法用户,抛弃
if (Data[0] != 255) return;//将非法用户的数据抛弃
try
{
byte[] buffer = new byte[cnt - 2];//申明一个字节数组,用于保存去除第一个字节码(即LanMsg协议编码)的其它数据(即消息实体)
Buffer.BlockCopy(Data, 2, buffer, 0, cnt - 2);//去除前两个字节码(即LanMsg协议编码)的其它数据为消息实体,将其保存于Buffer字节数组
switch (Data[1])// 取得第一个字节码,即LanMsg协议编码,根据编码判断用户发过来的请求为何种类型
{
case 0://服务器告诉用户密码错误
this.onErrorPassword(new DataArrivalEventArgs(buffer));
break;
case 5://服务器告诉用户登录成功
this.onUserScuccessLogin(new DataArrivalEventArgs(buffer));//触发用户成功登录事件
break;
case 6://服务器告诉用户与服务器处于联接状态
this.onUserOnlineChanageState(new DataArrivalEventArgs(buffer));//触发联接状态事件
break;
case 7://服务器返回“部分组织机构信息”
this.onGetDepartmentCollections(new DataArrivalEventArgs(buffer));//触发部门信息接收事件
break;
case 8://服务器返回“部分组织用户信息”
this.onGetUserCollections(new DataArrivalEventArgs(buffer));
break;
case 9://服务器通知有用户上线
this.onUserOnline(new DataArrivalEventArgs(buffer));//触发用户上线事件
break;
case 10://收到用户对话消息
this.onUserReceiveMsg(new DataArrivalEventArgs(buffer,Ip,Port ));//触发收到用户对话消息事件
break;
case 11://用户收到消息并回复
this.onUserReceiveMsgReturn(new DataArrivalEventArgs(buffer));//触发收到消息回复事件
break;
case 12://用户离线
this.onUserIsNotOnline(new DataArrivalEventArgs(buffer));//触发用户离线事件
break;
case 13://服务器通知用户已经在别处登录
this.onUserElseLogin();//触发用户别处登录事件
break;
case 14://用户发送文件请求事件
this.onUserFileSendRequest(new DataArrivalEventArgs(buffer, Ip, Port));//触发用户发送文件请求事件
break;
case 15://收到群发通知消息
this.onGroupMsg(new DataArrivalEventArgs(buffer));//处理群发通知消息
break;
case 16://对方要求打洞
this.onUdpPenetrate(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 17://用户UDP打洞成功
this.onUdpPenetrateSuccess(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 18://用户要求发送局域网IP地址与端口
this.onRecUserLocalIpPort(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 20://对方告诉自己向对方打洞成功
this.onAVRequest(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 21://对方告诉可以开始视频
this.onBeginAV(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 22://对方取消视频对话
this.onCancelAV(new DataArrivalEventArgs(buffer));
break;
case 23://服务器返回部分上线用户的信息
this.onGetOnlineUserCollections(new DataArrivalEventArgs(buffer));
break;
case 24://服务器告诉用户,密码修改成功
this.onChangePasswordSuccessful();
break;
case 25://对方桌面切图发送请求
this.onUserImageSendRequest(new DataArrivalEventArgs(buffer, Ip, Port));//触发用户发送文件请求事件
break;
}
}
catch { return; }//抛掉非法数据
}
#endregion
#region 服务器告诉用户,密码修改成功
/// <summary>
/// 密码修改成功
/// </summary>
private void onChangePasswordSuccessful( )
{
FormAccess.isChangePasswordSuccessful = true;
}
#endregion
#region 对方要求发送自己的本地局域网IP与端口
/// <summary>
/// 对方要求发送自己的本地局域网IP与端口
/// </summary>
/// <param name="e"></param>
private void onRecUserLocalIpPort(DataArrivalEventArgs e)
{
MessageBox.Show("用户发来本地局域网IP与端口:");
UserInfo tempUser=IMLibrary.Serializers.ByteToObj(e.Data) as UserInfo ;
if (tempUser == null) return;//非法数据则返回
exUser user = FormAccess.findUser(tempUser.UserID);
if (user == null) return;//非法数据则返回
user.IP = tempUser.IP;//将用户Internet IP设置为局域网IP
user.Port = tempUser.Port;//将用户Internet Port设置为局域网端口
user.isInLan = true;//将用户设置为局域网用户
MessageBox.Show("用户发来本地局域网IP与端口:" + user.IP.ToString() +"-"+ user.Port.ToString());
}
#endregion
#region 处理用户UDP打洞数据包
/// <summary>
/// 处理用户UDP打洞数据包
/// </summary>
/// <param name="e"></param>
private void onUdpPenetrate(DataArrivalEventArgs e)
{
string mtuValue = e.Data.Length.ToString();
string[] userStr = IMLibrary.TextEncoder.bytesToText(e.Data).Split('|');
//MessageBox.Show(userStr[0] +"要求打洞(" + mtuValue + ")") ;
exUser user = FormAccess.findUser(userStr[0]);
if (user == null) return;//如果用户不存在则返回
FormAccess.sendMsgToOneUser(17, IMLibrary.TextEncoder.textToBytes(FormAccess.selfInfo.UserID + "|" + mtuValue), user);//告诉对方打洞成功
}
/// <summary>
/// 处理打洞成功
/// </summary>
/// <param name="e"></param>
private void onUdpPenetrateSuccess(DataArrivalEventArgs e)
{
string[] userUdpPenInfo = IMLibrary.TextEncoder.bytesToText(e.Data).Split('|');
exUser user = FormAccess.findUser(userUdpPenInfo[0]);
if(user == null) return;//如果用户不存在则返回
user.isDirectCon = true;//表明用户与自己网络位置上处于直联,用户能够直接收到自己发送的任何消息,消息不需要服务器转发
try
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -