完善发送消息和接收消息接口
This commit is contained in:
@@ -15,11 +15,18 @@ namespace Interact
|
||||
//处理结果信息
|
||||
public const string Error = "Error";
|
||||
|
||||
//用户信息
|
||||
//获取用户信息
|
||||
public const string User = "User";
|
||||
public const string NickName = "NickName";
|
||||
public const string Motto = "Motto";
|
||||
public const string UGroup = "UGroup";
|
||||
public const string Photo = "Photo";
|
||||
public const string Total = "Total";
|
||||
public const string Count = "Count";
|
||||
|
||||
//消息
|
||||
public const string When = "When";
|
||||
public const string From = "From";
|
||||
public const string To = "To";
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -59,6 +59,7 @@ namespace Interact
|
||||
{
|
||||
tcpClient = new TcpClient();
|
||||
sendQueue = new BlockingCollection<Packet>();
|
||||
workingDictionary = new Dictionary<string, object>();
|
||||
Status = ClientStatus.Uninitialized;
|
||||
}
|
||||
|
||||
@@ -79,8 +80,7 @@ namespace Interact
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
workingDictionary.Clear(); //清空临时记录
|
||||
workingDictionary?.Clear(); //清空临时记录
|
||||
if (sendLoopThread != null)
|
||||
sendLoopThread.Abort();
|
||||
if (readLoopThread != null)
|
||||
@@ -102,11 +102,11 @@ namespace Interact
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="callback">数据发送完毕回调函数。注意,结果处理回调请设置OnLoginDone事件</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueLogin(string user, string password, Action<BaseHead> callback = null)
|
||||
public static bool QueueLogin(string user, string password, Action<ResultHead> callback = null)
|
||||
{
|
||||
JsonLogInfoHead logInfo = new JsonLogInfoHead()
|
||||
{
|
||||
Token = "",
|
||||
Token = Guid.NewGuid().ToString(),
|
||||
Operation = Operations.Login,
|
||||
User = user,
|
||||
Pwd = password
|
||||
@@ -127,19 +127,19 @@ namespace Interact
|
||||
/// <param name="to">消息接收者</param>
|
||||
/// <param name="callback">数据发送完毕时回调函数</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueSendMessage(string text, User to, Action<BaseHead> callback = null)
|
||||
public static bool QueueSendMessage(Message message, Action<ResultHead> callback = null)
|
||||
{
|
||||
JsonSendMessageHead jsonObj = new JsonSendMessageHead()
|
||||
{
|
||||
Token = "",
|
||||
Operation = Operations.SendMessage,
|
||||
To = to.Name,
|
||||
To = message.To.Name,
|
||||
NeedResult = DoesSendMessageReturn ? "1" : "0"
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = jsonObj,
|
||||
Data = Encoding.UTF8.GetBytes(text),
|
||||
Data = Encoding.UTF8.GetBytes(message.Text),
|
||||
CallBack = callback
|
||||
};
|
||||
return Send(packet);
|
||||
@@ -150,7 +150,7 @@ namespace Interact
|
||||
/// </summary>
|
||||
/// <param name="callback">数据发送完毕时回调函数</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueLogout(Action<BaseHead> callback = null)
|
||||
public static bool QueueLogout(Action<ResultHead> callback = null)
|
||||
{
|
||||
BaseHead jsonObj = new BaseHead()
|
||||
{
|
||||
@@ -171,7 +171,7 @@ namespace Interact
|
||||
/// </summary>
|
||||
/// <param name="callback">数据发送完毕时回调函数</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueGetUserList(Action<BaseHead> callback = null)
|
||||
public static bool QueueGetUserList(Action<ResultHead> callback = null)
|
||||
{
|
||||
BaseHead jsonObj = new BaseHead()
|
||||
{
|
||||
@@ -192,7 +192,7 @@ namespace Interact
|
||||
/// </summary>
|
||||
/// <param name="callback">数据发送完毕时回调函数</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueUpdateUserInfo(UserInfo userInfo, Action<BaseHead> callback = null)
|
||||
public static bool QueueUpdateUserInfo(UserInfo userInfo, Action<ResultHead> callback = null)
|
||||
{
|
||||
byte[] photoData = null; //头像数据
|
||||
//将头像数据转换到字符数组
|
||||
|
||||
+64
-11
@@ -28,29 +28,29 @@ namespace Interact
|
||||
|
||||
#region 处理服务器数据
|
||||
//根据包头信息处理数据
|
||||
private static void HandleAll(byte[] headData, byte[] data)
|
||||
private static void HandleAll(byte[] head, byte[] data)
|
||||
{
|
||||
string head = Encoding.UTF8.GetString(headData);
|
||||
JObject jsonObj = (JObject)JsonConvert.DeserializeObject(head);
|
||||
string headStr = Encoding.UTF8.GetString(head);
|
||||
JObject jsonObj = (JObject)JsonConvert.DeserializeObject(headStr);
|
||||
switch (jsonObj[AttrNames.Operation].ToString())
|
||||
{
|
||||
case Operations.Login:
|
||||
HandleLoginResult(jsonObj, data);
|
||||
break;
|
||||
case Operations.Panic:
|
||||
HandlePanic(GetResultHead(jsonObj));
|
||||
break;
|
||||
case Operations.Login:
|
||||
HandleLoginResult(jsonObj, data);
|
||||
break;
|
||||
case Operations.TransMessage:
|
||||
HandleMessage(jsonObj, data);
|
||||
break;
|
||||
case Operations.SendMessage:
|
||||
break;
|
||||
case Operations.Logout:
|
||||
break;
|
||||
case Operations.Offline:
|
||||
break;
|
||||
case Operations.UpdateUserInfo:
|
||||
break;
|
||||
case Operations.GetUsers:
|
||||
HandleGetUsersPack(jsonObj, data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -63,8 +63,9 @@ namespace Interact
|
||||
{
|
||||
Token = head[AttrNames.Token].ToString(),
|
||||
Operation = head[AttrNames.Operation].ToString(),
|
||||
Error = head[AttrNames.Error].ToString()
|
||||
};
|
||||
if (head[AttrNames.Error] != null)
|
||||
resultHead.Error = head[AttrNames.Error].ToString();
|
||||
return resultHead;
|
||||
}
|
||||
|
||||
@@ -102,15 +103,67 @@ namespace Interact
|
||||
OnLoginDone?.Invoke(resultHead, user);
|
||||
}
|
||||
|
||||
//收到消息
|
||||
private static void HandleMessage(JObject head, byte[] data)
|
||||
{
|
||||
//提取结果包头
|
||||
ResultHead resultHead = GetResultHead(head);
|
||||
Message message = new Message()
|
||||
{
|
||||
When = DateTime.Parse(head[AttrNames.When].ToString()),
|
||||
From = User.FromUserName(head[AttrNames.From].ToString()),
|
||||
To = User.Me,
|
||||
Text = Encoding.UTF8.GetString(data)
|
||||
};
|
||||
OnMessage?.Invoke(message);
|
||||
}
|
||||
|
||||
//处理获取用户列表的不连续返回包。当所有包接收完毕后返回给客户
|
||||
private static void HandleGetUsersPack(JObject head, byte[] data)
|
||||
{
|
||||
ResultHead result = GetResultHead(head);
|
||||
if (head[AttrNames.Error].ToString() != string.Empty)
|
||||
{
|
||||
OnGetUserListDone?.Invoke(GetResultHead(head), null);
|
||||
OnGetUserListDone?.Invoke(result, new User[0]);
|
||||
return;
|
||||
} //获取失败
|
||||
|
||||
else if (int.Parse(head[AttrNames.Count].ToString()) <= 0)
|
||||
{
|
||||
User[] us;
|
||||
if (workingDictionary.ContainsKey(result.Token))
|
||||
us = workingDictionary[result.Token] as User[];
|
||||
else
|
||||
us = new User[0];
|
||||
User.Users = us;
|
||||
OnGetUserListDone?.Invoke(result, us);
|
||||
return;
|
||||
} //获取完成
|
||||
//获取用户数据
|
||||
User user = new User
|
||||
{
|
||||
Name = head[AttrNames.User].ToString(),
|
||||
NickName = head[AttrNames.NickName].ToString(),
|
||||
Motto = head[AttrNames.Motto].ToString(),
|
||||
Group = (UserGroup)Enum.Parse(typeof(UserGroup), head[AttrNames.UGroup].ToString()),
|
||||
Photo = User.DefaultPhoto
|
||||
}; //基础数据
|
||||
if (int.Parse(head[AttrNames.Photo].ToString()) > 0)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(data);
|
||||
user.Photo = Image.FromStream(ms);
|
||||
} //头像数据
|
||||
//加入临时用户列表缓存
|
||||
User[] users;
|
||||
int total = int.Parse(head[AttrNames.Total].ToString()); //总用户数
|
||||
int count = int.Parse(head[AttrNames.Count].ToString()); //已接收用户数
|
||||
if (count > total)
|
||||
return;
|
||||
if (workingDictionary.ContainsKey(head[AttrNames.Token].ToString()))
|
||||
users = workingDictionary[result.Token] as User[];
|
||||
else
|
||||
users = new User[total];
|
||||
users[count - 1] = user;
|
||||
workingDictionary[result.Token] = users;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
+2
-26
@@ -3,32 +3,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
//定义Json序列化与反序列化时使用的数据结构,仅内部使用
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
#region 定义数据交互用到的数据结构(可能作为事件或回调函数的参数)
|
||||
//包头基本结构
|
||||
public class BaseHead
|
||||
{
|
||||
//请求ID,由发送方定义的随机字符串。如果接受方有返回数据应包含相同的Token
|
||||
//此特性暂时未启用,传空字符串即可
|
||||
public string Token;
|
||||
//操作类型,决定数据的其他内容
|
||||
public string Operation;
|
||||
}
|
||||
// 接受方返回的执行结果反馈包头,包含错误文本
|
||||
public class ResultHead : BaseHead
|
||||
{
|
||||
//错误文本,为空则执行成功
|
||||
public string Error;
|
||||
}
|
||||
//获取单一用户信息结果包头
|
||||
public class GetUserInfoResultHead : ResultHead
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 定义Json序列化与反序列化时使用的数据结构,仅内部使用
|
||||
//登录信息包头
|
||||
internal class JsonLogInfoHead : BaseHead
|
||||
{
|
||||
@@ -57,6 +35,4 @@ namespace Interact
|
||||
{
|
||||
public string User; //要获取头像的用户名
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
+20
-2
@@ -22,7 +22,7 @@ namespace Interact
|
||||
public const UInt32 MaxHeadLength = 4096; //最大包头长度
|
||||
public const UInt32 MaxMessageLength = 0x6400000; //最大数据长度
|
||||
*/
|
||||
public DateTime When { get; } //服务器接收时间
|
||||
public DateTime When; //服务器接收时间
|
||||
public User From; //消息发送者
|
||||
public User To; //消息接收者
|
||||
public string Text; //消息内容
|
||||
@@ -36,7 +36,7 @@ namespace Interact
|
||||
{
|
||||
public BaseHead Head; //包头
|
||||
public byte[] Data; //包内容
|
||||
public Action<BaseHead> CallBack; //数据发送完成的回调函数。注意,此时仅保证数据已发送,
|
||||
public Action<ResultHead> CallBack; //数据发送完成的回调函数。注意,此时仅保证数据已发送,
|
||||
//服务器可能并没有处理完成请求
|
||||
}
|
||||
//允许请求的操作列表。具体定义见设计文档
|
||||
@@ -51,4 +51,22 @@ namespace Interact
|
||||
public const string UpdateUserInfo = "UpdateUserInfo";
|
||||
public const string GetUsers = "GetUsers";
|
||||
}
|
||||
|
||||
#region 定义数据交互用到的数据结构(可能作为事件或回调函数的参数)
|
||||
//包头基本结构
|
||||
public class BaseHead
|
||||
{
|
||||
//请求ID,由发送方定义的随机字符串。如果接受方有返回数据应包含相同的Token
|
||||
public string Token;
|
||||
//操作类型,决定数据的其他内容
|
||||
public string Operation;
|
||||
}
|
||||
// 接受方返回的执行结果反馈包头,包含错误文本
|
||||
public class ResultHead : BaseHead
|
||||
{
|
||||
//错误文本,为空则执行成功
|
||||
public string Error;
|
||||
}
|
||||
//获取单一用户信息结果包头
|
||||
#endregion
|
||||
}
|
||||
|
||||
+33
-3
@@ -14,11 +14,13 @@ namespace Interact
|
||||
// 消息写入线程,向tcp连接写入数据
|
||||
private static void SendLoop()
|
||||
{
|
||||
Packet packet = null;
|
||||
NetworkStream stream = tcpClient.GetStream();
|
||||
try
|
||||
{
|
||||
foreach (Packet packet in sendQueue.GetConsumingEnumerable())
|
||||
foreach (Packet i in sendQueue.GetConsumingEnumerable())
|
||||
{
|
||||
packet = i; //为了在代码块外引用i
|
||||
//结束循环
|
||||
if (StormClient.Status != ClientStatus.Running)
|
||||
break;
|
||||
@@ -37,8 +39,14 @@ namespace Interact
|
||||
stream.Write(lenBuffer, 0, 4);
|
||||
if (length > 0)
|
||||
stream.Write(packet.Data, 0, packet.Data.Length);
|
||||
//发送完成回调
|
||||
packet.CallBack?.Invoke(packet.Head);
|
||||
//发送成功回调
|
||||
ResultHead result = new ResultHead
|
||||
{
|
||||
Token = packet.Head.Token,
|
||||
Operation = packet.Head.Operation,
|
||||
Error = ""
|
||||
};
|
||||
packet.CallBack?.Invoke(result);
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException ex)
|
||||
@@ -49,6 +57,28 @@ namespace Interact
|
||||
{
|
||||
HandleConnectionBroken(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
List<Packet> packets = new List<Packet>(sendQueue.Count + 1);
|
||||
if (packet != null)
|
||||
packets.Add(packet);
|
||||
while (sendQueue.TryTake(out packet))
|
||||
{
|
||||
if (packet != null)
|
||||
packets.Add(packet);
|
||||
}
|
||||
foreach (Packet p in packets)
|
||||
{
|
||||
//发送失败回调
|
||||
ResultHead result = new ResultHead
|
||||
{
|
||||
Token = packet.Head.Token,
|
||||
Operation = packet.Head.Operation,
|
||||
Error = "Client has stopped running."
|
||||
};
|
||||
packet.CallBack?.Invoke(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
//发送数据
|
||||
private static bool Send(Packet packet)
|
||||
|
||||
@@ -10,6 +10,29 @@ namespace Interact
|
||||
//用户
|
||||
public class User
|
||||
{
|
||||
//根据用户名匹配用户。如果用户不存在,则返回一个仅用户名有效的实例
|
||||
internal static User FromUserName(string userName)
|
||||
{
|
||||
if(User.Users != null)
|
||||
{
|
||||
foreach (User user in User.Users)
|
||||
{
|
||||
if (user.Name == userName)
|
||||
return user;
|
||||
}
|
||||
}
|
||||
User unidentifiedUser = new User
|
||||
{
|
||||
Name = userName,
|
||||
NickName = "",
|
||||
Motto = "",
|
||||
Group = UserGroup.User,
|
||||
Photo = User.DefaultPhoto
|
||||
};
|
||||
return unidentifiedUser;
|
||||
}
|
||||
internal static User[] Users; //用户列表。仅Interact内部访问
|
||||
|
||||
public static User Me; //当前用户
|
||||
public static Image DefaultPhoto; //默认头像
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace StormChat
|
||||
private void LogForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
StormClient.OnLoginDone += this.LoginDone;
|
||||
StormClient.OnMessage += this.ShowMessage;
|
||||
}
|
||||
private void btnLogin_Click(object sender, EventArgs e)
|
||||
{
|
||||
@@ -57,5 +58,10 @@ namespace StormChat
|
||||
else
|
||||
f.Invoke();
|
||||
}
|
||||
|
||||
private void ShowMessage(Interact.Message m)
|
||||
{
|
||||
MessageBox.Show(m.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user