Plane.Sdk3/PlaneGcsSdk.Contract.EhNetUWP/PLNet.cs
2017-02-27 02:02:19 +08:00

739 lines
27 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using System.IO;
using Windows.Storage.Streams;
using Windows.Networking;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Security.Cryptography.Core;
using Windows.Security.Cryptography;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class PLNet
{
#region Properties
public StreamOBJ MyStreamObj;
/// <summary>
/// 连接的IP
/// </summary>
public string ServerIP { get; protected set; }
/// <summary>
/// 连接的端口
/// </summary>
public int TCPPort { get; protected set; }
public bool IsClosing { get; protected set; }
public bool IsOpen { get; protected set; }
/// <summary>
/// 真实名
/// </summary>
public string MyNick { get; protected set; }
/// <summary>
/// 获取登录随机码
/// </summary>
public string MyRND { get { return sMyTempRnd; } }
/// <summary>
/// 发送文件列表
/// </summary>
public List<FileOBJ> SendFileList { get; protected set; }
/// <summary>
/// 接收文件列表
/// </summary>
public List<FileOBJ> RevFileList { get; protected set; }
/// <summary>
/// 用户列表
/// </summary>
public List<UserProperty> FriendList { get; protected set; }
/// <summary>
/// 发送流列表
/// </summary>
public List<StreamOBJ> SendStreamList { get; protected set; }
public List<StreamOBJ> RevStreamList { get; protected set; }
#endregion
#region Fields
string sMyTempRnd; //登录随机数
bool LoginFlag = false; //登录状态
string sMyID; //登录用户名
string sMyPassword; //登录密码
string sMyIP; //用户IP
Encoding _enconding;
int iStreamID = -1;
int iFileID = 0;
protected StreamSocket _socket; //连接对象
protected IInputStream _inputStream;
protected Stream _outputStream;
protected bool _canFlush = true;
protected const uint READ_BUFFER_SIZE = 2047;
#endregion
#region Events
public event EventHandler<LoginEventArgs> Login;
public event EventHandler<DiscoveredOneUserEventArgs> DiscoveredOneUser;
public event EventHandler RefreshFriendListCompleted;
public event EventHandler<UserStateChangeEventArgs> UserStateChange;
public event EventHandler Disconnect;
public event EventHandler<CommandArrivalEventArgs> CommandArrival;
public event EventHandler<ExceptionThrownEventArgs> ExceptionThrown;
public event EventHandler<StartSendFileEventArgs> StartSendFile;
#endregion
public PLNet()
{
FriendList = new List<UserProperty>();
SendFileList = new List<FileOBJ>();
RevFileList = new List<FileOBJ>();
SendStreamList = new List<StreamOBJ>();
RevStreamList = new List<StreamOBJ>();
}
#region Public Methods
/// <summary>
/// 建立连接
/// </summary>
/// <param name="sServerIP"></param>
/// <param name="sUsername"></param>
/// <param name="sPassword"></param>
/// <param name="md5Password"></param>
/// <returns></returns>
public async Task Start(string sServerIP, string sUsername, string sPassword, string md5Password = null)
{
Close();
IsClosing = false;
if (_enconding == null)
{
_enconding = await DBCSEncoding.GetDBCSEncoding("GB2312");
}
sMyID = sUsername;
if (md5Password == null)
sMyPassword = GetStrMd5Hash(sMyID + sPassword);
else
sMyPassword = md5Password;
ServerIP = sServerIP; //登录用户的IP地址
TCPPort = 52510; //登录用户的端口
_socket = new StreamSocket(); //创建连接对象
await _socket.ConnectAsync(new HostName(ServerIP), TCPPort.ToString()).AsTask().ConfigureAwait(false); //执行连接操作
IsOpen = true;
_inputStream = _socket.InputStream;
_outputStream = _socket.OutputStream.AsStreamForWrite();
await Task.Run(() => TCPClientThread());
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
IsClosing = true;
IsOpen = false;
_inputStream?.Dispose();
_outputStream?.Dispose();
_socket?.Dispose();
if (SendFileList != null)
SendFileList.Clear();
if (RevFileList != null)
RevFileList.Clear();
Disconnect?.Invoke(this, EventArgs.Empty); //触发事件Disconnect
}
/// <summary>
/// 发送命令
/// </summary>
/// <param name="friendIDs"></param>
/// <param name="msg"></param>
/// <returns></returns>
public async Task SendCommand(string friendIDs, string msg)
{
string commandtext = "*" + friendIDs + "|" + msg;
await SendCmd(commandtext);
}
/// <summary>
/// 发送数据流,给多个用户同时发送数据
/// </summary>
/// <param name="friendIDs"></param>
/// <param name="myData"></param>
/// <returns></returns>
public async Task SendStream(string friendIDs, byte[] myData)
{
string[] myFriends = friendIDs.Split(',');
for (int i = 0; i < myFriends.Length; i++)
{
iStreamID += 1;
MyStreamObj = new StreamOBJ();
MyStreamObj.StreamID = iStreamID;
MyStreamObj.StreamData = myData;
MyStreamObj.RevUserID = myFriends[i];
SendStreamList.Add(MyStreamObj);
string streamtext = "*" + myFriends[i] + "|SB|" + MyStreamObj.StreamID.ToString() + "|" + MyStreamObj.StreamData.Length.ToString();
await SendCmd(streamtext);
}
}
/// <summary>
/// 发送普通文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendFileCommon(string friendID, string[] sFilenames)
{
string filetype = "F";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送图片文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendPicture(string friendID, string[] sFilenames)
{
string filetype = "P";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送视频文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendVideo(string friendID, string[] sFilenames)
{
string filetype = "V";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送文件公共函数
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <param name="filetype"></param>
/// <returns></returns>
public async Task SendFileCommon(string friendID, string[] sFilenames, string filetype)
{
for (int i = 0; i < sFilenames.Length; i++)
{
FileOBJ tmpFileObj = new FileOBJ();
tmpFileObj.FileID = iFileID;
iFileID += 1;
FileInfo MyFileInfo = new FileInfo(sFilenames[i]);
tmpFileObj.Filename = MyFileInfo.Name;
tmpFileObj.FilePath = MyFileInfo.DirectoryName;
tmpFileObj.FileLength = MyFileInfo.Length;
tmpFileObj.FileModDate = filetype + MyFileInfo.LastWriteTime.ToString(); //filetype表示发送文件的类型
tmpFileObj.RevUserID = friendID;
tmpFileObj.State = FileState.WaitConfim;
tmpFileObj.tmpFileStream = new FileStream(sFilenames[i], FileMode.Open, FileAccess.Read);
SendFileList.Add(tmpFileObj);
StartSendFile?.Invoke(this, new StartSendFileEventArgs(SendFileList.Count - 1));
string filetext = "FB" + friendID + "|" + tmpFileObj.FileID.ToString() + "|" + tmpFileObj.Filename + "|" + tmpFileObj.FileLength.ToString() + "|" + tmpFileObj.FileModDate;
await SendCmd(filetext);
}
}
/// <summary>
/// 发送数据公共函数
/// </summary>
/// <param name="cmdStr"></param>
/// <param name="addBytes"></param>
/// <returns></returns>
public async Task SendCmd(string cmdStr, byte[] addBytes = null)
{
byte[] tmpSendbytes = null;
tmpSendbytes = _enconding.GetBytes(cmdStr);
int nret;
int strLen = LenB(cmdStr);
if (addBytes == null)
{
tmpSendbytes = BitConverter.GetBytes((ushort)strLen);
Array.Resize(ref tmpSendbytes, strLen + 2);
nret = _enconding.GetBytes(cmdStr, 0, cmdStr.Length, tmpSendbytes, 2);
}
else
{
byte[] tmpBytes;
long allLenth = strLen + addBytes.Length;
tmpBytes = BitConverter.GetBytes(allLenth);
Array.Resize(ref tmpBytes, strLen + 2);
nret = _enconding.GetBytes(cmdStr, 0, cmdStr.Length, tmpBytes, 2);
tmpSendbytes = AddByte(tmpBytes, addBytes);
}
try
{
if (tmpSendbytes != null)
{
await _outputStream.WriteAsync(tmpSendbytes, 0, tmpSendbytes.Length).ConfigureAwait(false);
if (_canFlush)
{
await _outputStream.FlushAsync().ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
_canFlush = false;
Close();
ExceptionThrown?.Invoke(this, new ExceptionThrownEventArgs(ex));
}
}
#endregion
#region Private Methods
/// <summary>
/// 启动一个接收数据的线程
/// </summary>
private async void TCPClientThread()
{
uint i; //接收到的数据的长度
byte[] byteBuffer = null; //暂存接收到的数据
int comLength;
bool ReadFlag = false;
bool nRet;
byte[] Tmpbyte;
IBuffer tempbuf = new Windows.Storage.Streams.Buffer(READ_BUFFER_SIZE); //建立一个buffer
await _inputStream.ReadAsync(tempbuf, READ_BUFFER_SIZE, InputStreamOptions.Partial);
i = tempbuf.Length;
byteBuffer = new byte[i];
tempbuf.CopyTo(byteBuffer); //将数据输出
while (i != 0)
{
if (byteBuffer.Length > 3)
{
comLength = BitConverter.ToUInt16(byteBuffer, 0);
if (LoginFlag == false && comLength > 70)
{
#region
if (byteBuffer.Length >= 2)
{
byte[] firstchar = new byte[1];
firstchar[0] = byteBuffer[1];
if (_enconding.GetString(firstchar) != "L")
i = 0;
}
else
{
ReadFlag = true;
}
#endregion
}
else
{
#region
if (byteBuffer.Length >= comLength + 1)
{
Tmpbyte = MidByte(byteBuffer, 3, comLength); //截取字节
if (Tmpbyte.Length < 4)
nRet = false;
nRet = await ProcessData(Tmpbyte);
if (nRet == true)
{
byteBuffer = RightByte(byteBuffer, byteBuffer.Length - comLength - 2); //截取字节
if (byteBuffer.Length <= 0)
ReadFlag = true;
}
else
{
return;
}
}
else
{
ReadFlag = true;
}
#endregion
}
}
else
{
ReadFlag = true;
}
if (ReadFlag == true)
{
#region
ReadFlag = false;
try
{
tempbuf = new Windows.Storage.Streams.Buffer(READ_BUFFER_SIZE); //建立一个buffer
await _inputStream.ReadAsync(tempbuf, READ_BUFFER_SIZE, InputStreamOptions.Partial);
i = tempbuf.Length;
byte[] addbyte = new byte[i];
tempbuf.CopyTo(addbyte);
byteBuffer = AddByte(byteBuffer, addbyte);
}
catch(Exception ex)
{
i = 0;
}
#endregion
}
}
}
/// <summary>
/// 处理接收到的数据
/// </summary>
/// <param name="tmpbyte"></param>
/// <returns></returns>
private async Task<bool> ProcessData(byte[] tmpbyte)
{
string recestr = _enconding.GetString(tmpbyte); //这里本应是GBK编码
UserProperty tmpUserinfo = new UserProperty();
int tmpIndex;
switch (recestr[0])
{
case 'R':
sMyTempRnd = recestr.Substring(1);
await SendCmd("L" + sMyID + "|" + GetStrMd5Hash(sMyPassword + sMyTempRnd));
sMyTempRnd = sMyTempRnd.Substring(0, sMyTempRnd.Length - 1);
break;
case 'U': //收到用户信息
string sUserinfo = recestr.Substring(1);
switch (sUserinfo[0])
{
#region
case 'A': //用户列表
#region
sUserinfo = sUserinfo.Substring(1);
tmpUserinfo.UserID = Fin(1, sUserinfo, "|");
tmpUserinfo.UserNick = Fin(2, sUserinfo, "|");
tmpUserinfo.UserIndex = FriendList.Count;
tmpUserinfo.UserMessage = new List<String>();
FriendList.Add(tmpUserinfo);
DiscoveredOneUser?.Invoke(this, new DiscoveredOneUserEventArgs(tmpUserinfo));
#endregion
break;
case 'O': //用户上线
#region
sUserinfo = sUserinfo.Substring(1);
tmpIndex = GetUserIndexByID(Fin(1, sUserinfo, "|"));
if (tmpIndex >= 0)
{
tmpUserinfo = FriendList[tmpIndex]; //修改用户在线状态
tmpUserinfo.UserOnline = true;
FriendList[tmpIndex] = tmpUserinfo;
UserStateChange?.Invoke(this, new UserStateChangeEventArgs(tmpUserinfo));
}
#endregion
break;
case 'F': //用户下线
#region
sUserinfo = sUserinfo.Substring(1);
string tmpFriendID = Fin(1, sUserinfo, "|");
tmpIndex = GetUserIndexByID(tmpFriendID);
if (tmpIndex >= 0)
{
tmpUserinfo = FriendList[tmpIndex];
tmpUserinfo.UserOnline = false;
FriendList[tmpIndex] = tmpUserinfo;
//处理发送文件残留
for (int i = 0; i < SendFileList.Count; i--)
{
if (SendFileList[i].RevUserID == tmpFriendID)
{
SendFileList[i].tmpFileStream.Dispose();
SendFileList.RemoveAt(i);
}
}
for (int j = 0; j < RevFileList.Count; j--)
{
if (RevFileList[j].RevUserID == tmpFriendID)
{
RevFileList[j].tmpFileStream.Dispose();
RevFileList.RemoveAt(j);
}
}
UserStateChange?.Invoke(this, new UserStateChangeEventArgs(tmpUserinfo));
}
#endregion
break;
case 'D':
break;
case 'C': //被别人添加为好友时会收到
break;
case 'E':
RefreshFriendListCompleted?.Invoke(this, EventArgs.Empty);
break;
default:
break;
#endregion
}
break;
case 'L': //登陆
recestr = recestr.Substring(1);
switch (recestr[0])
{
#region
case 'P':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginPwdError));
break;
case 'O':
LoginFlag = true;
MyNick = recestr.Substring(1).Split('|')[0];
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginOk));
await SendCmd("UG");
break;
case 'U':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginNoUser));
break;
case 'E':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginOtherError));
break;
default:
break;
#endregion
}
break;
case '*': //收到命令,格式为: *+FriendID+|+Msg
string tmpStr = recestr.Substring(1);
string tmpstr2 = Fin(2, tmpStr, "|");
switch (tmpstr2[0])
{
#region
case 'S':
break;
default:
string friendid = Fin(1, tmpStr, "|");
string msgcontent = tmpStr.Substring(tmpStr.IndexOf("|") + 1);
CommandArrival?.Invoke(this, new CommandArrivalEventArgs(friendid, msgcontent));
break;
#endregion
}
break;
default:
break;
}
return true;
}
private int LenB(string str)
{
return _enconding.GetBytes(str).Count();
}
/// <summary>
/// 获取一个字节数组中的某些字节从start个字节开始获取length个字节,第几个是从1开始的
/// </summary>
/// <param name="tbyte"></param>
/// <param name="start"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] MidByte(byte[] tbyte, int start, int length)
{
byte[] tmpMidByte = new byte[length];
//for (int i = 0; i < length; i++)
//{
// tmpMidByte[i] = tbyte[i + start - 1];
//}
for (int i = start - 1; i <= length - 1 + start - 1; i++)
{
tmpMidByte[i - (start - 1)] = tbyte[i];
}
return tmpMidByte;
}
/// <summary>
/// 获取某个字节数组的后面的字节获取length个字节
/// </summary>
/// <param name="tbyte"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] RightByte(byte[] tbyte, int length)
{
byte[] temRightByte = new byte[length];
temRightByte = MidByte(tbyte, tbyte.Length - length + 1, length);
return temRightByte;
}
/// <summary>
/// 获取某个字节数组的前面的字节获取length个字节
/// </summary>
/// <param name="tbyte"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] LeftByte(byte[] tbyte, int length)
{
byte[] temLeftByte = new byte[length];
temLeftByte = MidByte(tbyte, 1, length);
return temLeftByte;
}
/// <summary>
/// 拼接两个字节,将addbyte加在srcbyte后面
/// </summary>
/// <param name="srcbyte"></param>
/// <param name="addbyte"></param>
/// <returns></returns>
private byte[] AddByte(byte[] srcbyte, byte[] addbyte)
{
byte[] resultbyte = new byte[srcbyte.Length + addbyte.Length];
for (int i = 0; i < srcbyte.Length; i++)
{
resultbyte[i] = srcbyte[i];
}
for (int j = 0; j < addbyte.Length; j++)
{
resultbyte[j + srcbyte.Length] = addbyte[j];
}
return resultbyte;
}
/// <summary>
/// 根据ID获取列表中序号
/// </summary>
/// <param name="tmpUserID"></param>
/// <returns></returns>
protected int GetUserIndexByID(string tmpUserID)
{
for (int i = 0; i < FriendList.Count; i++)
{
if (FriendList.ElementAt(i).UserID == tmpUserID)
return i;
}
return -1;
}
/// <summary>
/// 分割字符串第Xnum个字符字符串为SrcStr分割特征为SpStr
/// </summary>
/// <param name="xnum"></param>
/// <param name="srcStr"></param>
/// <param name="spStr"></param>
/// <returns></returns>
private string Fin(int xnum, string srcStr, string spStr)
{
string[] tmpStr;
char[] FF = new char[1];
FF[0] = spStr[0];
tmpStr = srcStr.Split(FF);
if ((xnum > 0) && (xnum <= tmpStr.Length))
return tmpStr[xnum - 1];
else
return "";
}
/// <summary>
/// 计算字符串的MD5哈希值输入为字符串strtohash输出为字符串strHash
/// </summary>
/// <param name="strtohash"></param>
/// <returns></returns>
private string GetStrMd5Hash(string strtohash)
{
byte[] tmpbyte = _enconding.GetBytes(strtohash);
IBuffer buffMsg = CryptographicBuffer.CreateFromByteArray(tmpbyte);
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
IBuffer tmpbuffer = objAlgProv.HashData(buffMsg);
uint i = tmpbuffer.Length;
byte[] mybyte = new byte[i];
tmpbuffer.CopyTo(mybyte);
CryptographicBuffer.CopyToByteArray(tmpbuffer, out mybyte);
StringBuilder sBuilder = new StringBuilder();
for (int k = 0; k < mybyte.Length; k++)
{
sBuilder.Append(mybyte[k].ToString("x2"));
}
string strHash = sBuilder.ToString();
return strHash;
}
#endregion
}
#region Nested Type
/// <summary>
/// 用户信息结构体
/// </summary>
public struct UserProperty
{
public string UserID;
public string UserNick;
public string UserIP;
public int UserIndex;
public bool UserOnline;
public List<string> UserMessage;
}
/// <summary>
/// 文件状态
/// </summary>
public enum FileState
{
WaitConfim,
StartSend, //开始发送,等待确认
Sending, //正在发送中
reSend, //断点续传中
SendError, //发送错误
Completed, //发送完成
LoginOtherError, //其他错
StartReveice, //开始接收,等待数据
Receiving, //接收中
ReReceiving, //断点续传中
ReceiveError
}
/// <summary>
/// 登录状态
/// </summary>
public enum LoginState
{
LoginPwdError, //密码错
LoginOk, //登陆成功
LoginNoUser, //用户不存在
LoginOtherError, //其他错
}
/// <summary>
/// 文件结构体
/// </summary>
public struct FileOBJ
{
public string Filename;
public string FilePath;
public long FileLength;
public string FileModDate;
public int FileID;
public string SendUserID;
public string RevUserID;
public FileStream tmpFileStream;
public FileState State;
}
/// <summary>
/// 数据流结构体
/// </summary>
public struct StreamOBJ
{
public byte[] StreamData;
public ulong CurrPos;
public int StreamID;
public ulong Length;
public string SendUserID;
public string RevUserID;
}
#endregion
}