• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

zhaozongzhe

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

服务与用户界面之间的通信设计

服务与用户界面之间的通信分为两个部分,一是用户界面对服务的操作;二是服务不定时的向界面发送状态或者动作通知。

通常服务与界面之间的通信可以采用的方案有socket(tcp/udp)和命名管道两种方式,socket方案的优势是用户界面可以很容易的在另外一台计算机上操作远程计算机上的服务;而命名管道通常只能管理本机上的服务(最多可以在局域网上管理其它计算机而且需要配置)。

我们的选择是使用socket方案,同时采用TCP方式,因为相对UDP来说,TCP更加给人以可靠的感觉,除了需要处理“流”的分包,TCP相对UDP更加可靠一点。

然后为了处理命令和状态两种不同性质的通信,我们设计了两种socket,分别为CmdSocket和MsgSocket。

用户界面初始化时,创建MsgSocket,并长期与服务保持连接,之后服务的状态变化,都通过这个MsgSocket发送给用户界面,界面再将这些数据显示出来。这里MsgSocket会需要一个额外的线程。

用户的任何操作,需要向服务发送命令并等待回应,这时使用CmdSocket。CmdSocket使用短连接,发送数据并等待回应,然后返回。

采用这样的方式的好处是系统整体比较清晰。以下是我们在产品中使用的代码(通信的内容,是用的mini-xml):

 

View Code
  1 // 创建网络连接 
  2 SOCKET CmdSocket_CreateAndConnect(const CHAR *ip, WORD port); 
  3 // 网络发送 
  4 BOOL CmdSocket_Send(SOCKET cmdSock, const CHAR *data, int dataLen); 
  5 // 网络接收 
  6 BOOL CmdSocket_Receive(SOCKET cmdSock, CHAR **recvBuf, int *recvLen); 
  7 // 关闭连接 
  8 void CmdSocket_Close(SOCKET cmdSock);
  9 
 10 
 11 // ----------------------------------------------------------------------------------------- 
 12 // 异步消息接收线程 
 13 // 服务器会将一些通知信息通过此接口发送给客户端,格式为XML 
 14 // -----------------------------------------------------------------------------------------
 15 
 16 // 回调函数 
 17 typedef void (CALLBACK MSGSOCKET_CB)(CHAR *msgData, int msgLen);
 18 
 19 // 开始线程 
 20 BOOL BeginMsgSocketThread(MSGSOCKET_CB *msgSockCB, 
 21                           const CHAR *svrIp, WORD svrPort, 
 22                           const CHAR *svrPwd); 
 23 // 结束线程 
 24 void StopMsgSocketThread(); 
 25 
 26 
 27 static MSGSOCKET_CB *g_msgSockCB = NULL; 
 28 static SOCKET g_msgSock = INVALID_SOCKET; 
 29 static WSAEVENT g_msgSockEvent = NULL; 
 30 static WSAEVENT g_msgSockEventStop = NULL; 
 31 static WSAEVENT g_msgSockEventStopped = NULL; 
 32 static time_t g_msgSockNextConnectTime = 0; 
 33 static time_t g_msgSockLastReceiveTime = 0; 
 34 static CHAR *g_msgSockRecvBuf = NULL; 
 35 static int g_msgSockRecvSize = 0; 
 36 static int g_msgSockRecvLen = 0; 
 37 static CHAR g_msgSvrIp[32] = { 0 }; 
 38 static WORD g_msgSvrPort = 0; 
 39 static CHAR g_msgSvrPwd[32] = { 0 };
 40 
 41 __inline static BOOL Socket_Send(SOCKET cmdSock, const CHAR *data, int dataLen) 
 42 { 
 43     int sent, totalSent = 0;
 44 
 45     while (totalSent < dataLen) 
 46     { 
 47         sent = send(cmdSock, data+totalSent, dataLen-totalSent, 0); 
 48         if (sent == SOCKET_ERROR) return FALSE; 
 49         totalSent += sent; 
 50     } 
 51     return TRUE; 
 52 }
 53 
 54 static void MsgSocket_Close() 
 55 { 
 56     if (g_msgSock != INVALID_SOCKET) 
 57     { 
 58         closesocket(g_msgSock); 
 59         g_msgSock = INVALID_SOCKET; 
 60     } 
 61 }
 62 
 63 static void MsgSocket_Connect() 
 64 { 
 65     struct sockaddr_in addr; 
 66     time_t currTime;
 67 
 68     time(&currTime);
 69 
 70     if (currTime < g_msgSockNextConnectTime) return; 
 71     g_msgSockNextConnectTime = currTime + 5;
 72 
 73     g_msgSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 74 
 75     if (g_msgSock == INVALID_SOCKET) return;
 76 
 77     ResetEvent(g_msgSockEvent); 
 78     WSAEventSelect(g_msgSock, g_msgSockEvent, FD_CLOSE|FD_CONNECT|FD_READ);
 79 
 80     memset(&addr, 0, sizeof(addr)); 
 81     addr.sin_family = AF_INET; 
 82     addr.sin_addr.s_addr = inet_addr(g_msgSvrIp); 
 83     addr.sin_port = htons(g_msgSvrPort); 
 84     connect(g_msgSock, (struct sockaddr *)&addr, sizeof(addr)); 
 85 }
 86 
 87 static void MsgSocket_ProcessReceived() 
 88 { 
 89     int msgLen;
 90 
 91     while (1) 
 92     { 
 93         msgLen = 4 + ntohl(*((UINT32 *)g_msgSockRecvBuf)); 
 94         if (msgLen > g_msgSockRecvLen) break; 
 95         if (*(g_msgSockRecvBuf+4) != 30) 
 96         { g_msgSockRecvLen = 0; break; }
 97 
 98         g_msgSockCB((CHAR *)g_msgSockRecvBuf, msgLen);
 99 
100         if (msgLen < g_msgSockRecvLen) 
101         { 
102             memmove(g_msgSockRecvBuf, g_msgSockRecvBuf+msgLen, g_msgSockRecvLen-msgLen); 
103             g_msgSockRecvLen -= msgLen; 
104         } 
105         else 
106         { 
107             g_msgSockRecvLen = 0; 
108             break; 
109         } 
110     } 
111 }
112 
113 static void MsgSocket_Receive() 
114 { 
115     CHAR buf[8192], *pTmp; 
116     int received;
117 
118     while (1) 
119     { 
120         received = recv(g_msgSock, buf, 8192, 0); 
121         if (received == SOCKET_ERROR) break; 
122         if (received > 0) 
123         { 
124             if (!g_msgSockRecvBuf) 
125             { 
126                 g_msgSockRecvBuf = malloc(16384); 
127                 g_msgSockRecvSize = 16384; 
128                 g_msgSockRecvLen = received; 
129                 memcpy(g_msgSockRecvBuf, buf, received); 
130             } 
131             else 
132             { 
133                 if (g_msgSockRecvSize < g_msgSockRecvLen+received) 
134                 { 
135                     pTmp = (CHAR *)realloc(g_msgSockRecvBuf, g_msgSockRecvSize + 16384); 
136                     if (!pTmp) return; 
137                     g_msgSockRecvBuf = pTmp; 
138                     g_msgSockRecvSize += 16384; 
139                 } 
140                 memcpy(g_msgSockRecvBuf+g_msgSockRecvLen, buf, received); 
141                 g_msgSockRecvLen += received; 
142             } 
143             time(&g_msgSockLastReceiveTime); 
144         } 
145     } 
146 }
147 
148 static void MsgSocket_ProcessEvent() 
149 { 
150     WSANETWORKEVENTS ne;
151 
152     if (SOCKET_ERROR == WSAEnumNetworkEvents(g_msgSock, g_msgSockEvent, &ne)) 
153         return;
154 
155     if (ne.lNetworkEvents & FD_READ) 
156     { 
157         if (ne.iErrorCode[FD_READ_BIT]) 
158         { 
159             closesocket(g_msgSock); 
160             g_msgSock = INVALID_SOCKET; 
161             time(&g_msgSockNextConnectTime); 
162             g_msgSockNextConnectTime += 5; 
163             g_msgSockCB(NULL, -1); 
164             return; 
165         } 
166         MsgSocket_Receive(); 
167         MsgSocket_ProcessReceived(); 
168     } 
169     else if (ne.lNetworkEvents & FD_CONNECT) 
170     { 
171         if (ne.iErrorCode[FD_CONNECT_BIT]) 
172         { 
173             closesocket(g_msgSock); 
174             g_msgSock = INVALID_SOCKET; 
175             time(&g_msgSockNextConnectTime); 
176             g_msgSockNextConnectTime += 5; 
177             g_msgSockCB(NULL, -1); 
178             return; 
179         } 
180         //MsgSocket_SendRegister(); 
181     } 
182     else if (ne.lNetworkEvents & FD_CLOSE) 
183     { 
184         closesocket(g_msgSock); 
185         g_msgSock = INVALID_SOCKET; 
186         time(&g_msgSockNextConnectTime); 
187         g_msgSockNextConnectTime += 5; 
188         g_msgSockCB(NULL, -1); 
189     } 
190 }
191 
192 static unsigned __stdcall MsgSocketThreadProc(LPVOID param) 
193 { 
194     WSAEVENT eh[2]; 
195     DWORD dwWait;
196 
197     eh[0] = g_msgSockEvent; 
198     eh[1] = g_msgSockEventStop;
199 
200     while (1) 
201     { 
202         dwWait = WSAWaitForMultipleEvents(2, eh, FALSE, 1000, FALSE); 
203         if (dwWait == WSA_WAIT_EVENT_0) 
204             MsgSocket_ProcessEvent(); 
205         else if (dwWait == WSA_WAIT_TIMEOUT) 
206             MsgSocket_Connect(); 
207         else 
208             break; 
209     }
210 
211     WSASetEvent(g_msgSockEventStopped); 
212     return 0; 
213 }
214 
215 BOOL BeginMsgSocketThread(MSGSOCKET_CB *msgSockCB, 
216                           const CHAR *svrIp, WORD svrPort, 
217                           const CHAR *svrPwd) 
218 { 
219     g_msgSockCB = msgSockCB; 
220     strcpy_s(g_msgSvrIp, 32, svrIp); 
221     g_msgSvrPort = svrPort; 
222     strcpy_s(g_msgSvrPwd, 32, svrPwd); 
223     g_msgSockEvent = WSACreateEvent(); 
224     g_msgSockEventStop = WSACreateEvent(); 
225     g_msgSockEventStopped = WSACreateEvent(); 
226     CloseHandle((HANDLE)_beginthreadex(NULL, 0, MsgSocketThreadProc, NULL, 0, NULL));
227 
228     return TRUE; 
229 }
230 
231 void StopMsgSocketThread() 
232 { 
233     if (!g_msgSockEventStop) return;
234 
235     WSASetEvent(g_msgSockEventStop);
236 
237     while(TRUE) 
238     { 
239         if (WAIT_OBJECT_0==MsgWaitForMultipleObjects(1, &g_msgSockEventStopped, FALSE, INFINITE, QS_ALLINPUT)) 
240             break; 
241         else 
242         { 
243             MSG msg; 
244             PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 
245             DispatchMessage(&msg); 
246         } 
247     }
248 
249     WSACloseEvent(g_msgSockEvent); 
250     WSACloseEvent(g_msgSockEventStop); 
251     WSACloseEvent(g_msgSockEventStopped); 
252     g_msgSockEvent = NULL; 
253     g_msgSockEventStop = NULL; 
254     g_msgSockEventStopped = NULL; 
255     if (g_msgSockRecvBuf) free(g_msgSockRecvBuf);
256 
257     MsgSocket_Close(); 
258 }
259 
260 
261 // ------------------------------------------------------------------------------------------ 
262 // 
263 SOCKET CmdSocket_CreateAndConnect(const CHAR *ip, WORD port) 
264 { 
265     SOCKET cmdSock; 
266     struct sockaddr_in addr;
267 
268     cmdSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
269 
270     if (cmdSock == INVALID_SOCKET) return INVALID_SOCKET;
271 
272     memset(&addr, 0, sizeof(addr)); 
273     addr.sin_family = AF_INET; 
274     addr.sin_addr.s_addr = inet_addr(ip); 
275     addr.sin_port = htons(port); 
276     if (SOCKET_ERROR == connect(cmdSock, (struct sockaddr *)&addr, sizeof(addr))) 
277     { 
278         closesocket(cmdSock); 
279         return INVALID_SOCKET; 
280     }
281 
282     return cmdSock; 
283 }
284 
285 BOOL CmdSocket_Send(SOCKET cmdSock, const CHAR *data, int dataLen) 
286 { 
287     int sent, totalSent = 0;
288 
289     while (totalSent < dataLen) 
290     { 
291         sent = send(cmdSock, data+totalSent, dataLen-totalSent, 0); 
292         if (sent == SOCKET_ERROR) return FALSE; 
293         totalSent += sent; 
294     } 
295     return TRUE; 
296 }
297 
298 BOOL CmdSocket_Receive(SOCKET cmdSock, CHAR **recvBuf, int *recvLen) 
299 { 
300     int bufLen, cmdLen, recvLen1, recvTotal = 0; 
301     CHAR *buf, *bufNew;
302 
303     bufLen = 8192; 
304     buf = malloc(bufLen); 
305     if (!buf) return FALSE;
306 
307     recvTotal = 0; 
308     while (1) 
309     { 
310         recvLen1 = recv(cmdSock, buf+recvTotal, bufLen-recvTotal, 0); 
311         if (recvLen1 == SOCKET_ERROR) return FALSE;
312 
313         recvTotal += recvLen1; 
314         if (recvTotal < 5) return FALSE; 
315         cmdLen = 4 + ntohl(*((UINT32 *)buf)); 
316         if (*(buf+4) != 30) return FALSE; 
317         if (bufLen < cmdLen) 
318         { 
319             bufLen = ((cmdLen + 1) / 2048 + 1) * 2048; 
320             bufNew = (CHAR *)realloc(buf, bufLen); 
321             if (!bufNew) 
322             { 
323                 free(buf); 
324                 return FALSE; 
325             } 
326             buf = bufNew; 
327         } 
328         if (recvTotal > cmdLen) 
329         { 
330             free(buf); 
331             return FALSE; 
332         } 
333         if (recvTotal == cmdLen) break; 
334     } 
335     *recvBuf = buf; 
336     *recvLen = recvTotal;
337 
338     return TRUE; 
339 }
340 
341 void CmdSocket_Close(SOCKET cmdSock) 
342 { 
343     closesocket(cmdSock); 
344 } 

 

 这些代码摘自“网游更新平台”

posted on 2012-12-06 12:32  zhaozongzhe  阅读(437)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3