1. 无废话,先上图
2. 协议文档
1 协议概述
协议说明
通过本协议可以实现Client与Server之间的消息传递
1.2 连接方式
l Socket连接方式
以TCP/IP协议建立一个长连接, Server 监听IP和Port
1.3 术语表
ClientMsg Client=>Server 消息
ServerMsg Server=>Client 消息
Server 代表服务器
Client 代表客户端
IP ServerIP地址
Port 端口
2 消息包的定义—Socket连接
2.1 基本格式
消息包由消息头和消息体共同组成。
项目 |
说明 |
消息头 |
消息头部分 |
消息体 |
消息体部分 |
消息中利用到如下数据类型
类型 |
说明 |
Integer |
无符号整数 |
Text |
定长字符串,左对齐存储,空余位置补’\0’ |
消息头的格式
字段 |
长度(字节) |
类型 |
说明 |
Message Length |
4 |
Integer |
消息包总长度(字节) |
Command ID |
4 |
Integer |
命令ID |
Sequence ID |
4 |
Integer |
序列号 |
2.5 Client Msg 操作
命令方向:Client => Server
命令说明:用于向Server发送消息内容
Client 产生 CLIENT_MSG 消息包
Server 接收到后,返回CLIENT_MSG_RESP 消息包
CLIENT_MSG 命令的语法
字段 |
长度(字节) |
类型 |
说明 |
ID |
4 |
Integer |
消息ID |
Name |
50 |
Text |
物品名称 |
Class |
30 |
Text |
物品分类 |
Quantity |
4 |
Integer |
数量 |
Location |
30 |
Text |
存放地点 |
Reserve |
8 |
Text |
保留 |
CLIENT_MS_RESP应答的语法
字段 |
长度(字节) |
类型 |
说明 |
Result |
1 |
Integer |
执行命令是否成功。 0 =执行成功 其它:执行错误 |
Reserve |
8 |
Text |
保留 |
2.6 Server Msg 操作
命令方向:Server => Client
命令说明:用于Server发送信息到 Client
Server 产生 SERVER_MSG 消息包
Client 接收到后,返回SERVER_MSG_RESP 消息包
SERVER_MSG 命令的语法
字段 |
长度(字节) |
类型 |
说明 |
ID |
4 |
Integer |
消息ID |
|
|
|
|
Reserve |
8 |
Text |
保留 |
SERVER_MSG_RESP应答的语法
字段 |
长度(字节) |
类型 |
说明 |
Result |
1 |
Integer |
执行命令是否成功。 0:成功 其它:错误 |
Reserve |
8 |
Text |
保留 |
消息ID定义
消息ID名称 |
消息ID取值 |
BIND |
0x1 |
BIND_RESP |
0x80000001 |
UNBIND |
0x2 |
UNBIND_RESP |
0x80000002 |
ACTIVE_TEST |
0x3 |
ACTIVE_TEST_ RESP |
0x80000003 |
CLIENT_MSG |
0x10 |
CLIENT_MSG_RESP |
0x80000010 |
SERVER_MSG |
0x20 |
SERVER_MSG_RESP |
0x80000020 |
版本更新说明
3.代码
#region enum
public enum DEMO_COMMAND_ID : uint
{
DEMO_BIND = 0x00000001,
DEMO_BIND_RESP = 0x80000001,
DEMO_TERMINATE = 0x00000002, // 终止连接
DEMO_TERMINATE_RESP = 0x80000002, // 终止连接应答
DEMO_ACTIVE_TEST = 0x00000003, //激活测试
DEMO_ACTIVE_TEST_RESP = 0x80000003,
DEMO_CLIENT_MSG = 0x000000010,
DEMO_CLIENT_MSG_RESP = 0x80000010,
DEMO_SERVER_MSG = 0x00000020,
DEMO_SERVER_MSG_RESP = 0x80000020
}
public enum DEMO_EVENT_TYPE
{
OnBind=0,
OnBindResp=1,
OnUnbind=2,
OnUnbindResp=3,
OnTest = 4,
OnTestResp = 5,
OnClosed=6,
OnClientMsg=7,
OnClientMsgResp=8,
OnServerMsg=9,
OnServerMsgResp=10
}
#endregion
#region DEMO_CLIENT_MSG
public class DEMO_CLIENT_MSG
{
DEMO_MSG_HEADER header;
public ClientMsg clientMsg = new ClientMsg();
public DEMO_CLIENT_MSG(uint seq)
{
header = new DEMO_MSG_HEADER(DEMO_COMMAND_ID.DEMO_CLIENT_MSG);
header.Seq_ID = seq;
}
public DEMO_CLIENT_MSG(byte[] bs)
{
int index = 12;
index = index + 4;
clientMsg.Name = Encoding.Default.GetString(bs, index, GetRealLen(bs,index));
index = index + 50;
clientMsg.Class = Encoding.Default.GetString(bs, index, GetRealLen(bs, index));
index = index + 30;
clientMsg.Quantity = BIConvert.Bytes2UInt(bs,index);
index = index + 4;
clientMsg.Location = Encoding.Default.GetString(bs, index, GetRealLen(bs, index));
}
public byte[] GetBytes() //返回字节数印象
{
byte[] submitData = new byte[800];
int index = MSG.DEMO_MSG_HEADER.HeaderLength;
{
#region 进入填充包的过程
BIConvert.Int2Bytes(clientMsg.ID).CopyTo(submitData, index);
index = index + 4;
byte[] msg = Encoding.Default.GetBytes(clientMsg.Name);
msg.CopyTo(submitData, index);
index = index + 50;
msg = Encoding.Default.GetBytes(clientMsg.Class);
msg.CopyTo(submitData, index);
index = index + 30;
BIConvert.Int2Bytes(clientMsg.Quantity).CopyTo(submitData, index);
index = index + 4;
msg = Encoding.Default.GetBytes(clientMsg.Location);
msg.CopyTo(submitData, index);
index = index + 30;
index = index + 8;
#endregion
}
header.MSG_Length = (uint)index;
byte[] reVal = new byte[index];
header.GetBytes().CopyTo(reVal, 0);
for (int i = DEMO_MSG_HEADER.HeaderLength; i < reVal.Length; i++)
{
reVal[i] = submitData[i];
}
return (reVal);
}
private int GetRealLen(byte[] bts, int index)
{
int i = index;
for (; i < bts.Length; i++)
{
if (bts[i] == 0)
{
break;
}
}
return i - index;
}
}
public class DEMO_CLIENT_MSG_RESP
{
DEMO_MSG_HEADER header;
int _Result=0;
public int Result
{
set
{
this._Result = value;
}
get
{
return(this._Result);
}
}
public DEMO_CLIENT_MSG_RESP(byte[] bs)
{
this._Result = (int)bs[12+1];
}
public DEMO_CLIENT_MSG_RESP(uint seq)
{
header=new DEMO_MSG_HEADER(DEMO_COMMAND_ID.DEMO_CLIENT_MSG_RESP);
header.Seq_ID=seq;
header.MSG_Length=(uint)DEMO_MSG_HEADER.HeaderLength+1+8;
}
public byte[] GetBytes()
{
byte[] reVal=new byte[DEMO_MSG_HEADER.HeaderLength+1+8];
int index=0;
header.GetBytes().CopyTo(reVal,index);
index+=12;
reVal[index++]=(byte)this._Result;
index+=8; //reserve
return(reVal);
}
}
#endregion
#region DEMO_SERVER_MSG
public class DEMO_SERVER_MSG : AtomBase
{
DEMO_MSG_HEADER header;
public DEMO_SERVER_MSG(byte[] bs)
{
}
}
public class DEMO_SERVER_MSG_RESP
{
DEMO_MSG_HEADER header;
int _result=0;
public DEMO_SERVER_MSG_RESP(uint sequence)
{
header = new DEMO_MSG_HEADER(DEMO_COMMAND_ID.DEMO_SERVER_MSG_RESP);
header.Seq_ID = sequence;
header.MSG_Length = (uint)DEMO_MSG_HEADER.HeaderLength + 10 + 4;
}
public int Result
{
set
{
this._result = value;
}
}
public byte[] GetBytes()
{
byte[] reVal = new byte[MSG.DEMO_MSG_HEADER.HeaderLength + 10 + 4];
return (reVal);
}
}
#endregion
private void TimeCall(object stat)
{
log.Msg("TimeCall", DateTime.Now.ToString());
if (this.Connected)
{
this.Send_DEMO_COMMAND(DEMO.MSG.DEMO_COMMAND_ID.DEMO_ACTIVE_TEST);
this.CallEvent(DEMO.MSG.DEMO_EVENT_TYPE.OnTest, "Send Active_test");
}
else
{
//socket is closed!
}
}
private void CallEvent(MSG.DEMO_EVENT_TYPE event_type, object objValue)
{
if (this.onDEMOEvent != null)
{
MSG.DEMOEventArgs DEMOevent = new DEMO.MSG.DEMOEventArgs();
DEMOevent.DEMO_Event_Type = event_type;
switch (event_type)
{
case MSG.DEMO_EVENT_TYPE.OnClientMsg:
DEMOevent.clientMsg = (MSG.ClientMsg)objValue;
break;
case MSG.DEMO_EVENT_TYPE.OnServerMsg:
DEMOevent.serverMsg = (MSG.ServerMsg)objValue;
break;
default:
DEMOevent.Msg = (string)objValue;
break;
}
DEMOevent.SocketIndex = this.Index;
this.onDEMOEvent(this, DEMOevent);
}
}
#region Listen
private Socket ListenSocket;
private Thread ListenThread;
private static int MAXSOCKET = 20;
public static ManualResetEvent allDone = new ManualResetEvent(false);
private CDEMO[] SocClient = new CDEMO[MAXSOCKET];
public void StartListen()
{
ListenThread = new Thread(new ThreadStart(Start));
ListenThread.Start();
}
public void Start()
{
int Port = Convert.ToInt32(ini.GetValue("ServerListen", "Port"));
string IP = ini.GetValue("ServerListen", "IP");
try
{
IPEndPoint ipLocalEndPoint;
// IPAddress ipAddress = Dns.Resolve(IP).AddressList[0];
ipLocalEndPoint = new IPEndPoint(IPAddress.Parse(IP), Port); //Listen at Port 999
ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ListenSocket.Bind(ipLocalEndPoint);
ListenSocket.Listen(200);
statusBarPanel2.Text = IP + ":" + Port.ToString();
while (true)
{
allDone.Reset();
ListenSocket.BeginAccept(new AsyncCallback(AcceptCallback), ListenSocket);
allDone.WaitOne();
}
}
catch (Exception err)
{
log.Msg("Err_Listen", err.ToString()); ;
}
}
public void AcceptCallback(IAsyncResult ar)
{
try
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
int i = this.GetAvailbleSocket();
if ((i > -1) && (i < MAXSOCKET))
{
InitSocket(ref SocClient[i], i);
SocClient[i].socket = listener.EndAccept(ar);
SocClient[i].onDEMOEvent += new CDEMO.DEMOEventHandler(Form1_onDEMOEvent);
SocClient[i].StartServer();
}
}
catch (Exception err)
{
log.Msg("ERR_AcceptCallBack", err.ToString());
}
}
void Form1_onDEMOEvent(object sender, Atomsoft.CSocket.DEMO.MSG.DEMOEventArgs e)
{
switch (e.DEMO_Event_Type)
{
case Atomsoft.CSocket.DEMO.MSG.DEMO_EVENT_TYPE.OnClientMsg:
elv.AddMsg(new string[] { e.clientMsg.Name, e.clientMsg.Class, e.clientMsg.Quantity.ToString(), e.clientMsg.Location });
db.SaveMsg(e.clientMsg);
break;
}
}
private void InitSocket(ref CDEMO Soc, int nSocRef)
{
try
{
Soc = new CDEMO(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Soc.SocketID = nSocRef;
}
catch (Exception err)
{
log.Msg("ERR_InitSocket", err.ToString());
}
}
private int GetAvailbleSocket()
{
int i = -1;
for (i = 0; i < MAXSOCKET; i++)
{
try
{
if (SocClient[i] == null)
break;
else
{
if (!SocClient[i].socket.Connected)
{
SocClient[i] = null;
break;
}
}
}
catch (Exception err)
{
log.Msg("ERR_GetAvailbleSocket", err.ToString());
}
}
return i;
}
#endregion
private void Send_DEMO_COMMAND_RESP(MSG.DEMO_COMMAND_ID cmdID, uint seqid)
{
switch (cmdID)
{
case MSG.DEMO_COMMAND_ID.DEMO_ACTIVE_TEST:
MSG.DEMO_MSG_TEST_RESP active_test_resp = new MSG.DEMO_MSG_TEST_RESP(seqid);
this.SendBytes(active_test_resp.GetBytes());
break;
case MSG.DEMO_COMMAND_ID.DEMO_TERMINATE:
MSG.DEMO_MSG_TERMINATE_RESP terminate_resp = new MSG.DEMO_MSG_TERMINATE_RESP(seqid);
this.SendBytes(terminate_resp.GetBytes());
break;
case MSG.DEMO_COMMAND_ID.DEMO_CLIENT_MSG:
MSG.DEMO_CLIENT_MSG_RESP clientMsg_resp = new Atomsoft.CSocket.DEMO.MSG.DEMO_CLIENT_MSG_RESP(seqid);
this.SendBytes(clientMsg_resp.GetBytes());
break;
case MSG.DEMO_COMMAND_ID.DEMO_SERVER_MSG:
MSG.DEMO_SERVER_MSG_RESP serverMsg_Resp = new Atomsoft.CSocket.DEMO.MSG.DEMO_SERVER_MSG_RESP(seqid);
this.SendBytes(serverMsg_Resp.GetBytes());
break;
}
}
private void Send_DEMO_COMMAND(MSG.DEMO_COMMAND_ID cmdID)
{
switch (cmdID)
{
case MSG.DEMO_COMMAND_ID.DEMO_TERMINATE:
MSG.DEMO_MSG_TERMINATE terminate = new MSG.DEMO_MSG_TERMINATE(this.getNextSequence());
this.SendBytes(terminate.GetBytes());
break;
case MSG.DEMO_COMMAND_ID.DEMO_ACTIVE_TEST:
MSG.DEMO_MSG_TEST active_test = new MSG.DEMO_MSG_TEST(this.getNextSequence());
this.SendBytes(active_test.GetBytes());
break;
}
}
private void Send_DEMO_BIND_RESP(int result, uint seqid)
{
MSG.DEMO_BIND_RESP Bindresp = new Atomsoft.CSocket.DEMO.MSG.DEMO_BIND_RESP(seqid);
Bindresp.Result = result;
this.SendBytes(Bindresp.GetBytes());
}
private void Send_DEMO_BIND()
{
MSG.DEMO_BIND bind = new MSG.DEMO_BIND(this.getNextSequence());
bind.UserName = "DEMO";
bind.Password = "DEMO";
this.SendBytes(bind.GetBytes());
log.Msg("SendBind", "bind");
}
private void SendBytes(byte[] sendbytes)
{
this.SendBytes(sendbytes, 3);
}