// Deal.cpp: implementation of the CDeal class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ClientMML.h"
#include "Deal.h"
#include<winsock2.h>
#include<stdio.h>
#include "Shlwapi.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDeal::CDeal()
{
}
CDeal::~CDeal()
{
}
/************************连接服务器*************************/
int CDeal::connectMML(int& m_sockfd, CString& m_ip, int& m_port)
{
SOCKADDR_IN m_server_addr;
int m_result;
memset((char*)&m_server_addr,'/0',(int)sizeof(m_server_addr));
//Socket地址结构体的创建
m_server_addr.sin_family = AF_INET;
m_server_addr.sin_addr.S_un.S_addr = inet_addr(m_ip);
m_server_addr.sin_port = htons( m_port );
//创建流式套接字,基于TCP(SOCK_STREAM)
m_sockfd = socket( AF_INET, SOCK_STREAM, 0 );
if (0 >= m_sockfd)
{
AfxMessageBox("socket creat failed/n");
exit(0);
}
//Socket的内部函数,建立客户端到服务器的连接
m_result = connect(m_sockfd, (SOCKADDR*)&m_server_addr, sizeof(SOCKADDR));
if (0 != m_result)
{
AfxMessageBox("connect server failed/n");
exit(0);
}
return 1;
}
/**************MML客户端消息编码封装成可识别消息****************/
int CDeal::Encode(MsgInfo & sendMsg,char * sendBuff, int & sendLen, int send_type)
{
//此处省略异常处理过程
//如果是心跳消息,编码方式如下
if (TYPE_OF_HB_MSG == send_type)
{
int temp_len;
char * p_num, hb_checksum [MAX_HB_CHCKSUM];
temp_len = 0;
strncpy(sendBuff+ temp_len,MSG_STARTTAG, MSG_STARTTAG_LEN);
temp_len += MSG_STARTTAG_LEN;
p_num = Int2ToHex(HB_MSG_LEN);
strncpy(sendBuff + temp_len, p_num, MAX_HB_MSG_LEN);
temp_len += MAX_HB_MSG_LEN;
strncpy (sendBuff + temp_len, HB_CONTENT, MAX_HB_CONTENT_LEN);
temp_len = MSG_STARTTAG_LEN + MAX_HB_MSG_LEN;
GetChkSum(MAX_HB_MSG_LEN,sendBuff + temp_len,hb_checksum);
temp_len = HB_MSG_LEN - MAX_HB_CHCKSUM;
strncpy(sendBuff + temp_len, hb_checksum, MAX_HB_CHCKSUM);
printf("/ncode HB secceed!/n%s",sendBuff);
return Success;
}
//如果是普通消息,编码如下
int msglen,cmdlen,len;
char *p,chksum[MSG_CHKSUM_LEN];
char *pTx[ ] = { "TXBEG" , "TXCON" , "TXCAN" , "TXEND" };
char *pDlg[ ] = { "DLGLGN" , "DLGBEG" , "DLGCON" , "DLGEND" };
//打印发送的消息
PrintMsg(sendMsg);
//计算消息长度
cmdlen=strlen(sendMsg.cmd);
msglen=MAX_HEAD_LEN+cmdlen;
len=(4 - msglen % 4);
msglen+=len;
sendLen=msglen+MSG_COMM_LEN;
memset(sendBuff,' ',MAX_MSG_LEN);
len=0;
//拼装消息开始标志
strncpy(sendBuff+len, MSG_STARTTAG, MSG_STARTTAG_LEN);
len+=MSG_STARTTAG_LEN;
//拼装消息长度
p=Int2ToHex(msglen);
strncpy(sendBuff+len, p, MSG_INFOLEN_LEN);
len+=MSG_INFOLEN_LEN;
//拼装消息头
strncpy(sendBuff+len, MSG_VERSION, MAX_LEN_VERSION);
len+=MAX_LEN_VERSION;
strncpy(sendBuff+len, MSG_TERMINAL, MAX_LEN_TERMINAL);
len+=MAX_LEN_TERMINAL;
strncpy(sendBuff+len,sendMsg.service, strlen(sendMsg.service));
len+=MAX_LEN_SERVNAME;
//拼装会话头
p=Int4ToHex(sendMsg.snLogin);
strncpy(sendBuff+len, p, MAX_LEN_DLGID);
len+=MAX_LEN_DLGID;
strncpy(sendBuff+len,pDlg[sendMsg.dlgCtrl],strlen(pDlg[sendMsg.dlgCtrl]));
len+=MAX_LEN_DLGCTRL;
strncpy(sendBuff+len, MSG_DLGRSVD, MAX_LEN_DLGRSVD);
len+=MAX_LEN_DLGRSVD;
//拼装事务头
// p=Int4ToHex(sendMsg.sequence);
sprintf(p, "%4x", sendMsg.sequence);
strncpy(sendBuff+len, p, MAX_LEN_TXID);
len+=MAX_LEN_TXID;
strncpy(sendBuff+len,pTx[sendMsg.txCtrl],strlen(pTx[sendMsg
.txCtrl]));
len+=MAX_LEN_TXCTRL;
strncpy(sendBuff+len, MSG_TXRSVD, MAX_LEN_TXRSVD);
len+=MAX_LEN_TXRSVD;
//拼装操作信息
strncpy(sendBuff+len, sendMsg.cmd, cmdlen);
//拼装校验和
len=MSG_STARTTAG_LEN + MSG_INFOLEN_LEN;
GetChkSum(msglen,sendBuff+len,chksum);
len=sendLen-MSG_CHKSUM_LEN;
strncpy(sendBuff+len, chksum, MSG_CHKSUM_LEN);
return Success;
}
/***********对接受到的消息进行解码****************/
int CDeal::Decode(MsgInfo &recMsg,char* recBuff,int& recLen, int recv_type)
{
//此处省略异常处理过程
int msglen,len,tmpInt;
char chksum[MSG_CHKSUM_LEN],tmpStr[MAX_MSG_LEN];
char *pTx[ ] = { "TXBEG" , "TXCON" , "TXCAN" , "TXEND" };
char *pDlg[ ] = { "DLGLGN" , "DLGBEG" , "DLGCON" , "DLGEND" };
len=0;
//解码消息开始标志
strncpy(tmpStr, recBuff+len, MSG_STARTTAG_LEN);
tmpStr[MSG_STARTTAG_LEN]='/0';
len+=MSG_STARTTAG_LEN;
if(strncmp(tmpStr,MSG_STARTTAG,MSG_STARTTAG_LEN) != 0)
{
printf("Msg head error.");
return NotCMD;
}
//解码消息长度
strncpy(tmpStr, recBuff+len, MSG_INFOLEN_LEN);
tmpStr[MSG_INFOLEN_LEN]='/0';
len+=MSG_INFOLEN_LEN;
HexToInt2(tmpStr,tmpInt);
msglen=tmpInt;
if ( recv_type == TYPE_OF_CMD_MSG )
{
if(msglen+MSG_COMM_LEN != recLen)
{
printf("Msg length error.");
return Failure;
}
}
//如果是心跳消息,解码方式如下
if ( recv_type == TYPE_OF_HB_MSG )
{
tmpInt=HB_MSG_LEN;
char HBtempStr[HB_MSG_LEN],HBStr[HB_MSG_LEN];
strncpy(HBtempStr, recBuff, tmpInt);
HBtempStr[tmpInt]='/0';
StrTrim(HBtempStr," ");
strcpy(HBStr,"HBHB");
for (int i=0; i<4; i++)
{
if( recBuff[MSG_STARTTAG_LEN+MAX_HB_MSG_LEN+i]!=HBStr[i])
{
return Failure;
}
}
return Success;
}
//如果是普通消息,解码如下
//解码消息头
strncpy(tmpStr, recBuff+len, MAX_LEN_VERSION);
tmpStr[MAX_LEN_VERSION]='/0';
len+=MAX_LEN_VERSION;
StrTrim(tmpStr," ");
strncpy(tmpStr, recBuff+len, MAX_LEN_TERMINAL);
tmpStr[MAX_LEN_TERMINAL]='/0';
len+=MAX_LEN_TERMINAL;
StrTrim(tmpStr," ");
strncpy(tmpStr, recBuff+len, MAX_LEN_SERVNAME);
tmpStr[MAX_LEN_SERVNAME]='/0';
len+=MAX_LEN_SERVNAME;
StrTrim(tmpStr," ");
strcpy(recMsg.service,tmpStr);
//解码会话头
strncpy(tmpStr, recBuff+len, MAX_LEN_DLGID);
tmpStr[MAX_LEN_DLGID]='/0';
len+=MAX_LEN_DLGID;
HexToInt4(tmpStr,tmpInt);
recMsg.snLogin=tmpInt;
strncpy(tmpStr, recBuff+len, MAX_LEN_DLGCTRL);
tmpStr[MAX_LEN_DLGCTRL]='/0';
len+=MAX_LEN_DLGCTRL;
StrTrim(tmpStr," ");
for(tmpInt=0;tmpInt<4;tmpInt++) if(strcmp(pDlg[tmpInt],tmpStr)==0) break;
recMsg.dlgCtrl=tmpInt;
strncpy(tmpStr, recBuff+len, MAX_LEN_DLGRSVD);
tmpStr[MAX_LEN_DLGRSVD]='/0';
len+=MAX_LEN_DLGRSVD;
//解码事务头
strncpy(tmpStr, recBuff+len, MAX_LEN_TXID);
tmpStr[MAX_LEN_TXID]='/0';
len+=MAX_LEN_TXID;
HexToInt4(tmpStr,tmpInt);
recMsg.sequence=tmpInt;
strncpy(tmpStr, recBuff+len, MAX_LEN_TXCTRL);
tmpStr[MAX_LEN_TXCTRL]='/0';
len+=MAX_LEN_TXCTRL;
StrTrim(tmpStr," ");
for(tmpInt=0;tmpInt<4;tmpInt++) if(strcmp(pTx[tmpInt],tmpStr)==0) break;
recMsg.txCtrl=tmpInt;
strncpy(tmpStr, recBuff+len, MAX_LEN_TXRSVD);
tmpStr[MAX_LEN_TXRSVD]='/0';
len+=MAX_LEN_TXRSVD;
//解码操作信息
tmpInt=msglen-(MAX_HEAD_LEN);
strncpy(tmpStr, recBuff+len, tmpInt);
tmpStr[tmpInt]='/0';
len+=tmpInt;
StrTrim(tmpStr," ");
strcpy(recMsg.cmd, tmpStr);
//解码校验和
strncpy(tmpStr, recBuff+len, MSG_CHKSUM_LEN);
tmpStr[MSG_CHKSUM_LEN]='/0';
len=MSG_STARTTAG_LEN + MSG_INFOLEN_LEN;
GetChkSum(msglen,recBuff+len,chksum);
if(strncmp(tmpStr,chksum,MSG_CHKSUM_LEN) != 0)
{
printf("Msg chksum error.");
return Failure;
}
//解码完毕,打印消息
PrintMsg(recMsg);
return Success;
}
/*************************发送消息***************************/
int CDeal::SendMsg(int m_sockfd, char* sendBuff)
{
send(m_sockfd, sendBuff, sizeof(sendBuff), 0);
return 0;
}
/*************************接收消息**************************/
int CDeal::RecvMsg(int m_sockfd, char* recvBuff)
{
int recLen = recv( m_sockfd, recvBuff, sizeof(recvBuff),0 );
if(recLen>0)
{
printf("/nreceive login ack message.../n/n");
//解码消息并获取相应的操作结果
Decode(recvMsg,recvBuff,recLen,TYPE_OF_CMD_MSG);
}
return 0;
}
/*Function: GetChkSum
Description: 实现对"消息头 + 会话头 + 事务头 + 操作信息"按32位异或
Calls:
Called By:
Input: len是指"消息头 + 会话头 + 事务头 + 操作信息"四者的长度和。
Buf是指"消息头 + 会话头 + 事务头 + 操作信息"四者结合的字符数组。
Output: res是指按32位异或得到的结果
Return:
Others:
*************************************************/
void CDeal::GetChkSum(int len, PSTR buf, PSTR res)
{
memset(res, 0, 4); //AAA格式的校验码为4字节
for(int i=0; i<len; i+=4)
{
res[0]^=(buf+i)[0];
res[1]^=(buf+i)[1];
res[2]^=(buf+i)[2];
res[3]^=(buf+i)[3];
}
res[0]=~res[0];
res[1]=~res[1];
res[2]=~res[2];
res[3]=~res[3];
}
/*********************打印消息******************/
void CDeal::PrintMsg(MsgInfo msg)
{
}
char* CDeal::Int2ToHex(unsigned int _Int2)
{
char tmp[5];
char *_hex = new char;
sprintf(tmp, "%04x", _Int2);
for(int i=0; i<4; i++)
{
sprintf(_hex+sizeof(_hex),"//x%x",tmp[i]);
}
return _hex;
}
char* CDeal::Int4ToHex(int _Int4)
{
char tmp[9];
char *_hex = new char;
sprintf(tmp,"%08x", _Int4);
for(int i=0; i<8; i++)
{
sprintf(_hex+i*4, "//x%x", tmp[i]);
}
return _hex;
}
void CDeal::HexToInt2(char* _hex, int _Int2)
{
sscanf(_hex,"%4x", &_Int2);
}
void CDeal::HexToInt4(char* _hex, int _Int4)
{
sscanf(_hex, "%8x", &_Int4);
}
// Deal.h: interface for the CDeal class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_DEAL_H__0C860618_5F96_42D5_AD20_C5EA3C0CF0ED__INCLUDED_)
#define AFX_DEAL_H__0C860618_5F96_42D5_AD20_C5EA3C0CF0ED__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//宏定义
#define MAX_LEN_VERSION 4
#define MAX_LEN_TERMINAL 8
#define MAX_LEN_SERVNAME 8
#define MAX_LEN_DLGCTRL 6
#define MAX_LEN_TXID 8
#define MAX_LEN_TXCTRL 6
#define MAX_LEN_TXRSVD 4
#define MAX_MSG_LEN 65536
#define MAX_HEAD_LEN 56
#define MSG_STARTTAG_LEN 4
#define MSG_INFOLEN_LEN 4
#define MSG_CHKSUM_LEN 4
#define MSG_COMM_LEN 12
#define MAX_HB_MSG_LEN 4
#define MAX_HB_CONTENT_LEN 4
#define MAX_HB_CHCKSUM 4
#define HB_MSG_LEN 16
#define MAX_LEN_DLGID 8
#define MAX_LEN_DLGRSVD 4
#define MSG_STARTTAG "/x1C/x1D/x1E/x1F"
#define MSG_VERSION "1.00"
#define MSG_TERMINAL "internal"
#define MSG_TXRSVD " "
#define MSG_DLGRSVD " "
#define HB_CONTENT "HBHB"
#define Failure 0
#define Success 1
#define NotCMD 2
#define TYPE_OF_HB_MSG 1000
#define TYPE_OF_CMD_MSG 1001
struct MsgInfo
{
char* cmd;
char* service;
int snLogin;
int dlgCtrl;
int sequence;
int txCtrl;
};
class CDeal
{
public:
CDeal();
virtual ~CDeal();
public:
int connectMML(int& m_sockfd, CString& m_ip, int& m_port) ;
int Encode(MsgInfo &sendMsg,char* sendBuff, int& sendLen, int send_type);
int Decode(MsgInfo &recMsg,char* recBuff,int& recLen, int recv_type);
int SendMsg(int m_sockfd, char* sendBuff);
int RecvMsg(int m_sockfd, char* recvBuff);
void PrintMsg(MsgInfo msg);
void GetChkSum(int len, PSTR buf, PSTR res);
char* Int2ToHex(unsigned int _Int2);
char* Int4ToHex(int _Int4);
void HexToInt2(char* _hex, int _Int2);
void HexToInt4(char* _hex, int _Int4);
public:
MsgInfo recvMsg;
MsgInfo sendMsg;
};
#endif // !defined(AFX_DEAL_H__0C860618_5F96_42D5_AD20_C5EA3C0CF0ED__INCLUDED_)
本文介绍了一个MML客户端如何实现与服务器的连接、消息的编码与解码、发送及接收等核心功能。针对不同类型的MML消息,如心跳消息和普通指令消息,详细展示了其处理流程和技术细节。
6万+

被折叠的 条评论
为什么被折叠?



