Socket编程实例
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 |
版本更新说明
版本号 |
说明 |
V 1.0 |
建立接口协议 |
|
|
|
|
#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); }