Plane.Sdk3/PlaneGcsSdk.Contract.EhNetUWP/PLNet.cs

739 lines
27 KiB
C#
Raw Permalink Normal View History

2017-02-27 02:02:19 +08:00
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
}