merge到master
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
//Json数据的字段访问字符串
|
||||
public static class AttrNames
|
||||
{
|
||||
//基本信息
|
||||
public const string Token = "Token";
|
||||
public const string Operation = "Operation";
|
||||
|
||||
//处理结果信息
|
||||
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";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
//定义StormClient私有字段
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
public partial class StormClient
|
||||
{
|
||||
//TCP客户端
|
||||
private static TcpClient tcpClient;
|
||||
//消息发送队列
|
||||
private static BlockingCollection<Packet> sendQueue;
|
||||
//数据读取线程
|
||||
private static Thread readLoopThread;
|
||||
//数据发送线程
|
||||
private static Thread sendLoopThread;
|
||||
//某些请求需要持续的等待服务器返回数据包,然后将所有数据包处理后提供给用户,
|
||||
// 此字段用于暂存这些未接收完全的数据包。它的key是对应请求的Token字串。
|
||||
private static Dictionary<string, object> workingDictionary;
|
||||
|
||||
//属性控制字段,任何地方都不应该修改它们
|
||||
//发送消息时是否要求服务器返回处理结果。由DoesSendMessageReturn属性控制,不要直接修改这个字段
|
||||
private static volatile bool doesSendMessageReturnResult = false;
|
||||
//当前连接状态。由Status属性控制,不要直接修改这个字段
|
||||
private static volatile ClientStatus clientStatus = ClientStatus.Uninitialized;
|
||||
|
||||
//线程安全-锁
|
||||
//更改连接状态锁
|
||||
private static object statusLocker = new object();
|
||||
//"发送消息时是否要求服务器返回处理结果"Falg锁
|
||||
private static object doesSendMessageReturnLocker = new object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
//StormClient对数据的处理相关内容
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
public partial class StormClient
|
||||
{
|
||||
//处理连接中断异常。
|
||||
private static void HandleConnectionBroken(Exception ex)
|
||||
{
|
||||
lock (statusLocker)
|
||||
{
|
||||
if (Status != ClientStatus.Running)
|
||||
return;
|
||||
statusLocker = ClientStatus.Stopped;
|
||||
tcpClient.Close();
|
||||
OnDisconnect?.Invoke(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#region 处理服务器数据
|
||||
//根据包头信息处理数据
|
||||
private static void HandleAll(byte[] head, byte[] data)
|
||||
{
|
||||
string headStr = Encoding.UTF8.GetString(head);
|
||||
JObject jsonObj = (JObject)JsonConvert.DeserializeObject(headStr);
|
||||
switch (jsonObj[AttrNames.Operation].ToString())
|
||||
{
|
||||
case Operations.Panic:
|
||||
HandlePanic(GetResultHead(jsonObj));
|
||||
break;
|
||||
case Operations.Login:
|
||||
HandleLoginResult(jsonObj, data);
|
||||
break;
|
||||
case Operations.TransMessage:
|
||||
HandleMessage(jsonObj, data);
|
||||
break;
|
||||
case Operations.SendMessage:
|
||||
HandleSendMessageResult(GetResultHead(jsonObj));
|
||||
break;
|
||||
case Operations.Offline:
|
||||
HandlePanic(GetResultHead(jsonObj));
|
||||
break;
|
||||
case Operations.UpdateUserInfo:
|
||||
HandleUpdateUserInfoDone(GetResultHead(jsonObj));
|
||||
break;
|
||||
case Operations.GetUsers:
|
||||
HandleGetUsersPack(jsonObj, data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//提取基本结果包头结构
|
||||
private static ResultHead GetResultHead(JObject head)
|
||||
{
|
||||
ResultHead resultHead = new ResultHead
|
||||
{
|
||||
Token = head[AttrNames.Token].ToString(),
|
||||
Operation = head[AttrNames.Operation].ToString(),
|
||||
};
|
||||
if (head[AttrNames.Error] != null)
|
||||
resultHead.Error = head[AttrNames.Error].ToString();
|
||||
return resultHead;
|
||||
}
|
||||
|
||||
//处理服务器异常断开连接消息
|
||||
private static void HandlePanic(ResultHead head)
|
||||
{
|
||||
SetStatus(ClientStatus.Stopped);
|
||||
OnPanic?.Invoke(head);
|
||||
}
|
||||
|
||||
//处理登录反馈消息
|
||||
private static void HandleLoginResult(JObject head, byte[] data)
|
||||
{
|
||||
//提取结果包头
|
||||
ResultHead resultHead = GetResultHead(head);
|
||||
//发起登录完成事件
|
||||
if (head[AttrNames.Error].ToString() != "")
|
||||
{
|
||||
OnLoginDone?.Invoke(resultHead, null);
|
||||
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);
|
||||
} //用户头像数据
|
||||
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 HandleSendMessageResult(ResultHead head)
|
||||
{
|
||||
OnSendMessageDone?.Invoke(head);
|
||||
}
|
||||
|
||||
//处理掉线、强制登出
|
||||
private static void HandleOffiline(ResultHead head)
|
||||
{
|
||||
SetStatus(ClientStatus.Stopped);
|
||||
OnOffline?.Invoke(head);
|
||||
}
|
||||
|
||||
//处理更改信息结果
|
||||
private static void HandleUpdateUserInfoDone(ResultHead head)
|
||||
{
|
||||
OnUpdateUserInfoDone?.Invoke(head);
|
||||
}
|
||||
|
||||
//处理获取用户列表的不连续返回包。当所有包接收完毕后返回给客户
|
||||
private static void HandleGetUsersPack(JObject head, byte[] data)
|
||||
{
|
||||
ResultHead result = GetResultHead(head);
|
||||
if (head[AttrNames.Error].ToString() != string.Empty)
|
||||
{
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
//StormClient读取数据相关内容
|
||||
namespace Interact
|
||||
{
|
||||
public partial class StormClient
|
||||
{
|
||||
// 数据读取线程,从tcp连接读取数据
|
||||
private static void ReadLoop()
|
||||
{
|
||||
NetworkStream stream = StormClient.tcpClient.GetStream();
|
||||
try
|
||||
{
|
||||
while (StormClient.Status == ClientStatus.Running)
|
||||
{
|
||||
byte[] head = ReadDataWithLength(stream);
|
||||
byte[] data = ReadDataWithLength(stream);
|
||||
HandleAll(head, data);
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException ex)
|
||||
{
|
||||
HandleConnectionBroken(ex);
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
HandleConnectionBroken(ex);
|
||||
}
|
||||
}
|
||||
// 从网络流读取数据
|
||||
private static byte[] ReadDataWithLength(NetworkStream stream)
|
||||
{
|
||||
byte[] lenBuffer = new byte[4]; //数据长度
|
||||
//获取数据长度
|
||||
stream.Read(lenBuffer, 0, 4);
|
||||
int length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenBuffer, 0));
|
||||
if (length <= 0)
|
||||
return null;
|
||||
//读取数据
|
||||
byte[] data = new byte[length];
|
||||
stream.Read(data, 0, length);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
//StormClient发送数据相关内容
|
||||
namespace Interact
|
||||
{
|
||||
public partial class StormClient
|
||||
{
|
||||
// 消息写入线程,向tcp连接写入数据
|
||||
private static void SendLoop()
|
||||
{
|
||||
Packet packet = null;
|
||||
NetworkStream stream = tcpClient.GetStream();
|
||||
//json序列化时忽略值为null的项
|
||||
JsonSerializerSettings setting = new JsonSerializerSettings();
|
||||
setting.NullValueHandling = NullValueHandling.Ignore;
|
||||
try
|
||||
{
|
||||
//阻塞式的从发送队列中取出数据
|
||||
foreach (Packet i in sendQueue.GetConsumingEnumerable())
|
||||
{
|
||||
packet = i; //为了在代码块外引用i
|
||||
//结束循环
|
||||
if (StormClient.Status != ClientStatus.Running)
|
||||
break;
|
||||
//向tcp连接写数据
|
||||
byte[] lenBuffer; //数据长度缓存
|
||||
byte[] headData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(packet.Head, setting));
|
||||
//写包头
|
||||
lenBuffer = BitConverter.GetBytes((UInt32)IPAddress.HostToNetworkOrder(headData.Length));
|
||||
stream.Write(lenBuffer, 0, 4);
|
||||
stream.Write(headData, 0, headData.Length);
|
||||
//写数据
|
||||
int length = 0;
|
||||
if (packet.Data != null)
|
||||
length = packet.Data.Length;
|
||||
lenBuffer = BitConverter.GetBytes((UInt32)IPAddress.HostToNetworkOrder(length));
|
||||
stream.Write(lenBuffer, 0, 4);
|
||||
if (length > 0)
|
||||
stream.Write(packet.Data, 0, packet.Data.Length);
|
||||
//发送成功回调
|
||||
ResultHead result = new ResultHead
|
||||
{
|
||||
Token = packet.Head.Token,
|
||||
Operation = packet.Head.Operation,
|
||||
Error = ""
|
||||
};
|
||||
packet.CallBack?.Invoke(result);
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException ex)
|
||||
{
|
||||
HandleConnectionBroken(ex);
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (sendLoopThread == null || !sendLoopThread.IsAlive)
|
||||
return false;
|
||||
//加入数据发送队列等待
|
||||
sendQueue.Add(packet);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
//连接中断
|
||||
public delegate void ConnectionBrokenHandler(Exception ex);
|
||||
//通用请求结果处理
|
||||
public delegate void ResultHandler(ResultHead head);
|
||||
//消息到达事件处理
|
||||
public delegate void MessageHandler(Message msg);
|
||||
//登录反馈到达
|
||||
public delegate void LoginDoneHandler(ResultHead head, User user);
|
||||
//获取用户列表结果处理
|
||||
public delegate void GetUserListDoneHandler(ResultHead head, User[] users);
|
||||
|
||||
/// <summary>
|
||||
/// 与服务器进行数据通信,并向外部提供一系列通信接口
|
||||
/// </summary>
|
||||
public static partial class StormClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接中断事件。注意,此事件并不保证连接中断时总是触发,例如主动关闭连接、登出操作
|
||||
/// </summary>
|
||||
public static event ConnectionBrokenHandler OnDisconnect;
|
||||
/// <summary>
|
||||
/// 服务器异常消息处理事件
|
||||
/// </summary>
|
||||
public static event ResultHandler OnPanic;
|
||||
/// <summary>
|
||||
/// 服务器强制注销登陆事件
|
||||
/// </summary>
|
||||
public static event ResultHandler OnOffline;
|
||||
/// <summary>
|
||||
/// 消息到达事件
|
||||
/// </summary>
|
||||
public static event MessageHandler OnMessage;
|
||||
/// <summary>
|
||||
/// 发送消息处理完成反馈事件(仅在DoesSendMessageReturn为true时有效)
|
||||
/// </summary>
|
||||
public static event ResultHandler OnSendMessageDone;
|
||||
/// <summary>
|
||||
/// 更新用户信息结果处理事件
|
||||
/// </summary>
|
||||
public static event ResultHandler OnUpdateUserInfoDone;
|
||||
/// <summary>
|
||||
/// 登录结果处理事件
|
||||
/// </summary>
|
||||
public static event LoginDoneHandler OnLoginDone;
|
||||
/// <summary>
|
||||
/// 获取用户列表结果处理事件
|
||||
/// </summary>
|
||||
public static event GetUserListDoneHandler OnGetUserListDone;
|
||||
|
||||
//当前连接状态
|
||||
public static ClientStatus Status
|
||||
{
|
||||
get { lock (statusLocker) { return clientStatus; } }
|
||||
}
|
||||
//发送消息时是否要求服务器返回处理结果
|
||||
public static bool DoesSendMessageReturn
|
||||
{
|
||||
get { lock (doesSendMessageReturnLocker) { return doesSendMessageReturnResult; } }
|
||||
set { lock (doesSendMessageReturnLocker) { doesSendMessageReturnResult = value; } }
|
||||
}
|
||||
|
||||
|
||||
static StormClient()
|
||||
{
|
||||
tcpClient = new TcpClient();
|
||||
sendQueue = new BlockingCollection<Packet>();
|
||||
workingDictionary = new Dictionary<string, object>();
|
||||
SetStatus(ClientStatus.Uninitialized);
|
||||
}
|
||||
|
||||
//设置当前连接状态
|
||||
internal static void SetStatus(ClientStatus value)
|
||||
{
|
||||
lock (statusLocker) { clientStatus = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化客户端,连接服务器。如果成功则启动数据接收和发送线程。
|
||||
/// 注意,当网络不稳定时此方法可能会阻塞。
|
||||
/// </summary>
|
||||
/// <returns>如果已连接到服务器返回true,否则返回false。</returns>
|
||||
public static bool Initialize()
|
||||
{
|
||||
if (StormClient.tcpClient.Connected)
|
||||
return true;
|
||||
try
|
||||
{
|
||||
StormClient.tcpClient.Connect(Interact.Properties.Resources.RemoteServerAddr, int.Parse(Interact.Properties.Resources.RemoteServerPort));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
workingDictionary?.Clear(); //清空临时记录
|
||||
if (sendLoopThread != null)
|
||||
sendLoopThread.Abort();
|
||||
if (readLoopThread != null)
|
||||
readLoopThread.Abort();
|
||||
//启动数据收发线程
|
||||
sendLoopThread = new Thread(new ThreadStart(SendLoop));
|
||||
readLoopThread = new Thread(new ThreadStart(ReadLoop));
|
||||
sendLoopThread.IsBackground = readLoopThread.IsBackground = true;
|
||||
SetStatus(ClientStatus.Running);
|
||||
sendLoopThread.Start();
|
||||
readLoopThread.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登录。此操作为异步操作,服务器返回结果后产生OnLoginDone事件。
|
||||
/// </summary>
|
||||
/// <param name="user">用户名</param>
|
||||
/// <param name="password">密码</param>
|
||||
/// <param name="callback">数据发送完毕回调函数。注意,结果处理回调请设置OnLoginDone事件</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueLogin(string user, string password, Action<ResultHead> callback = null)
|
||||
{
|
||||
JsonLogInfoHead logInfo = new JsonLogInfoHead()
|
||||
{
|
||||
Token = Guid.NewGuid().ToString(),
|
||||
Operation = Operations.Login,
|
||||
User = user,
|
||||
Pwd = password
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = logInfo,
|
||||
Data = null,
|
||||
CallBack = callback
|
||||
};
|
||||
return Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求发送一条消息。异步,此方法将请求放入请求队列后返回。
|
||||
/// </summary>
|
||||
/// <param name="text">要发送的消息文本</param>
|
||||
/// <param name="to">消息接收者</param>
|
||||
/// <param name="callback">数据发送完毕时回调函数。</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueSendMessage(Message message, Action<ResultHead> callback = null)
|
||||
{
|
||||
JsonSendMessageHead jsonObj = new JsonSendMessageHead()
|
||||
{
|
||||
Token = "",
|
||||
Operation = Operations.SendMessage,
|
||||
To = message.To.Name,
|
||||
NeedResult = DoesSendMessageReturn ? "1" : "0"
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = jsonObj,
|
||||
Data = Encoding.UTF8.GetBytes(message.Text),
|
||||
CallBack = callback
|
||||
};
|
||||
return Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求登出。异步,此方法将请求放入请求队列后返回。
|
||||
/// </summary>
|
||||
/// <param name="callback">数据发送完毕时回调函数。</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueLogout(Action<ResultHead> callback = null)
|
||||
{
|
||||
BaseHead jsonObj = new BaseHead()
|
||||
{
|
||||
Token = "",
|
||||
Operation = Operations.Logout,
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = jsonObj,
|
||||
Data = null,
|
||||
CallBack = callback
|
||||
};
|
||||
bool success = Send(packet);
|
||||
SetStatus(ClientStatus.Stopped);
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求用户列表。异步,此方法将请求放入请求队列后返回。
|
||||
/// </summary>
|
||||
/// <param name="callback">数据发送完毕时回调函数。</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueGetUserList(Action<ResultHead> callback = null)
|
||||
{
|
||||
BaseHead jsonObj = new BaseHead()
|
||||
{
|
||||
Token = "",
|
||||
Operation = Operations.GetUsers,
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = jsonObj,
|
||||
Data = null,
|
||||
CallBack = callback
|
||||
};
|
||||
return Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求更新当前登录用户信息。异步,此方法将请求放入请求队列后返回。
|
||||
/// </summary>
|
||||
/// <param name="userInfo">新的用户信息,如果某项值为null,则不改变该项。</param>
|
||||
/// <param name="callback">数据发送完毕时回调函数。</param>
|
||||
/// <returns>成功将请求加入发送队列返回true,否则返回false。</returns>
|
||||
public static bool QueueUpdateUserInfo(UserInfo userInfo, Action<ResultHead> callback = null)
|
||||
{
|
||||
byte[] photoData = null; //头像数据
|
||||
//将头像数据转换到字符数组
|
||||
if (userInfo.Photo != null)
|
||||
{
|
||||
MemoryStream memStream = new MemoryStream();
|
||||
userInfo.Photo.Save(memStream, userInfo.Photo.RawFormat);
|
||||
photoData = new byte[memStream.Length];
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
memStream.Read(photoData, 0, photoData.Length);
|
||||
}
|
||||
//构建数据包
|
||||
JsonUserInfoHead jsonObj = new JsonUserInfoHead()
|
||||
{
|
||||
Token = Guid.NewGuid().ToString(),
|
||||
Operation = Operations.UpdateUserInfo,
|
||||
NickName = userInfo.NickName,
|
||||
Password = userInfo.Password,
|
||||
Motto = userInfo.Motto,
|
||||
Photo = userInfo.Photo == null ? 0 : photoData.Length
|
||||
};
|
||||
Packet packet = new Packet
|
||||
{
|
||||
Head = jsonObj,
|
||||
Data = photoData,
|
||||
CallBack = callback
|
||||
};
|
||||
return Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 客户端连接状态
|
||||
/// </summary>
|
||||
public enum ClientStatus
|
||||
{
|
||||
Uninitialized, //未启动
|
||||
Running, //运行中
|
||||
Stopped //已停止
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
public class ConnectionBrokenException : Exception
|
||||
{
|
||||
public ConnectionBrokenException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{CEF054AF-95B7-4B88-934E-02705FEEA554}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Interact</RootNamespace>
|
||||
<AssemblyName>Interact</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>.\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Client.cs" />
|
||||
<Compile Include="Exception.cs" />
|
||||
<Compile Include="Client-Fields.cs" />
|
||||
<Compile Include="Client-Handle.cs" />
|
||||
<Compile Include="jsonObject.cs" />
|
||||
<Compile Include="Message.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Client-Read.cs" />
|
||||
<Compile Include="Client-Send.cs" />
|
||||
<Compile Include="AttrNames.cs" />
|
||||
<Compile Include="User.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
//定义一则用户接收到的消息
|
||||
public class Message
|
||||
{
|
||||
public Message() { }
|
||||
public Message(string text, User Receiver)
|
||||
{
|
||||
When = DateTime.Now;
|
||||
From = User.Me;
|
||||
To = Receiver;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
/*保留
|
||||
public const UInt32 MaxHeadLength = 4096; //最大包头长度
|
||||
public const UInt32 MaxMessageLength = 0x6400000; //最大数据长度
|
||||
*/
|
||||
public DateTime When; //服务器接收时间
|
||||
public User From; //消息发送者
|
||||
public User To; //消息接收者
|
||||
public string Text; //消息内容
|
||||
|
||||
//将消息保存到数据库(保留)
|
||||
protected bool Save() { return false; }
|
||||
}
|
||||
|
||||
//从服务器接收的原始数据封包
|
||||
internal class Packet
|
||||
{
|
||||
public BaseHead Head; //包头
|
||||
public byte[] Data; //包内容
|
||||
public Action<ResultHead> CallBack; //数据发送完成的回调函数。注意,此时仅保证数据已发送,
|
||||
//服务器可能并没有处理完成请求
|
||||
}
|
||||
//允许请求的操作列表。具体定义见设计文档
|
||||
public static class Operations
|
||||
{
|
||||
public const string Panic = "Panic";
|
||||
public const string TransMessage = "TransMessage";
|
||||
public const string SendMessage = "SendMessage";
|
||||
public const string Login = "Login2";
|
||||
public const string Logout = "Logout";
|
||||
public const string Offline = "Offline";
|
||||
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
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Interact")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Interact")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("cef054af-95b7-4b88-934e-02705feea554")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Interact.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Interact.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to mattuy.top.
|
||||
/// </summary>
|
||||
internal static string RemoteServerAddr {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteServerAddr", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 3727.
|
||||
/// </summary>
|
||||
internal static string RemoteServerPort {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteServerPort", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="RemoteServerAddr" xml:space="preserve">
|
||||
<value>mattuy.top</value>
|
||||
</data>
|
||||
<data name="RemoteServerPort" xml:space="preserve">
|
||||
<value>3727</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Drawing;
|
||||
|
||||
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; //默认头像
|
||||
|
||||
public string Name; //用户名
|
||||
public string NickName; //昵称
|
||||
public string Motto; //个性签名
|
||||
public UserGroup Group; //用户组
|
||||
public Image Photo; //头像
|
||||
}
|
||||
|
||||
//更新用户信息时新的用户信息。如果项值为null则不更改相应的信息
|
||||
public class UserInfo
|
||||
{
|
||||
public string Password = null; //新密码
|
||||
public string NickName = null; //新昵称
|
||||
public string Motto = null; //新签名
|
||||
public Image Photo = null; //新头像
|
||||
}
|
||||
|
||||
//用户类型
|
||||
public enum UserGroup
|
||||
{
|
||||
User, //普通用户
|
||||
Vip, //会员
|
||||
Admin, //管理员
|
||||
Group //群组
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
//定义Json序列化与反序列化时使用的数据结构,仅内部使用
|
||||
|
||||
namespace Interact
|
||||
{
|
||||
//登录信息包头
|
||||
internal class JsonLogInfoHead : BaseHead
|
||||
{
|
||||
public string User;
|
||||
public string Pwd;
|
||||
}
|
||||
|
||||
//发送消息包头
|
||||
internal class JsonSendMessageHead : BaseHead
|
||||
{
|
||||
public string To; //消息接收者用户名
|
||||
public string NeedResult = "0"; //是否要求服务器返回处理结果。否传“0”
|
||||
}
|
||||
|
||||
//更新用户信息包头
|
||||
internal class JsonUserInfoHead : BaseHead
|
||||
{
|
||||
public string NickName = null;
|
||||
public string Password = null;
|
||||
public string Motto = null;
|
||||
public int Photo = 0; //新头像大小
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user