2009-11-09 28 views
0

请注意,这不是作业,我在开始这个新线程之前搜索过。我得到了Store an int in a char array?编码,将整数解码为字符数组

我正在寻找答案,但没有得到任何满意的答案在上述线程。

这是我的要求:我想要编码我的数据(比如一个整数)在一个字节数组中,然后通过网络传输,然后在另一端解码并处理它。

这里的编码部分:

const int MAX=5; 
uint32_t a = 0xff00ffaa; 
char byte_array[1024]; // this is the array to be transferred over the network 
char buff[MAX]=""; 
sprintf(buff,"%4d",a); 
memcpy(byte_array,buff,4); 
// fill remaining stuff in the byte array and send it over the network 

这里的解码部分:

const int MAX=5; 
char buff[MAX]=""; 
strncat(buff,byte_array,4) 

int i=atoi(buff); 
// Work with i 

这里是我的问题:

1)在上述代码的可移植性?我想这是(请纠正我)

2)现在,我希望编码的字节数组与3个字节(但整数大小为4),即说整数存储0x00ffaabb,我只是希望字节数组有ff int 0th index aa在第一个索引中,bb在第二个索引中。怎么做?

snprinf似乎没有工作或可能是我失去了一些东西。

已经实施任何网络协议的人可以轻松地帮助我。 解码逻辑仍然会工作我猜。 (strncat(buff,byte_array,3)后跟atoi函数调用)。

这里的协议这样说:

 
    --------+--------+--------+--------+------------------------------ 
    |Version| 3  byte length | Remaining stuff 
    --------+--------+--------+--------+------------------------------ 

版是1个字节,然后是消息的3字节的长度。

我希望能澄清我的问题

+0

谢谢大家的及时帮助。我知道了。我很喜欢从RFC实现一个协议,因此需要所有这些信息。 谢谢tonne :) – ghayalcoder 2009-11-10 09:40:15

回答

5

您正在存储为ASCII,您应该在其中存储字节本身。

的编码应该是这样的:

uint32_t a = 0xff00ffaa; 
unsigned char byte_array[1024]; 

通知我是怎样使你的目标阵列无符号,以表明它的“原始字节”,而不是实际的字符。

byte_array[0] = a >> 24; 
byte_array[1] = a >> 16; 
byte_array[2] = a >> 8; 
byte_array[3] = a >> 0; 

这将序列变量a为使用big-endian字节顺序,这是排序默认为许多网络协议的byte_array四个第一字节。

您可能还想在这里看到我的答案:question 1577161

1

至少要携带你应该考虑在编码可能不同的字节顺序。

您是否确实需要实施新的网络消息协议? NASA IPC或Sun RPC不适合你吗?它们都足够稳定,美国国家航空航天局更容易启动,RPC看起来更广泛(是的,它已准备好使用,图书馆可用于大多数流行的系统)。

  • 对于RPC尝试 '人RPC'
  • 对于NASA IPC看here
2

你在做什么将排序的工作。您不会传输数据的字节 - 您正在传输数据的数值。因此,对于要发送的数据而言,大小为5的缓冲区太小(0xFF00FFAA的数值为4278255530 - 10个字节)。

要转让,你需要做这样的事情字节以下(假设小端):

编码:

char array[1024]; // outgoing network data 
int next = 0; 

array[next++] = value & 0xFF; 
array[next++] = (value >> 8) & 0xFF; 
array[next++] = (value >> 16) & 0xFF; 
array[next++] = (value >> 24) & 0xFF; 

这些语句去掉值的字节,并将它们分配给连续值在你的数组中。

解码:

char array[1024]; // incoming network data 
int next = 0; 

value = 0; 
value |= (int)*((unsigned char*)array)[next++]; 
value |= (int)*((unsigned char*)array)[next++] << 8; 
value |= (int)*((unsigned char*)array)[next++] << 16; 
value |= (int)*((unsigned char*)array)[next++] << 24; 

这些语句拉字节移出该阵列和把它们放回入值。

如果你想尝试优化你的网络格式,而不是传输字节,你可以消除一些数据。但请记住,您的发件人和收件人需要彼此了解需要什么 - 因此需要就传递的数据元素的类型或长度进行一些沟通。

3

1)它的工作,因为你使用的字符数组的运输,我会使用二进制协议个人。如果你可以使用你的变量的4个字节,我会看看htonl/ntohl函数(它们几乎在每个unix上,并且在windows上自从w2k开始),否则参见下面的

2)用二进制协议编码将

uint32_t a = 0xff00ffaa; 
char byte_array[1024]; // this is the array to be transferred over the network 

// leave byte_array[0] for version byte 
// leave the high order byte in a since you want only the 3 lowest 
byte_array[1] = (char)((a & 0x00FF0000)>>16); 
byte_array[2] = (char)((a & 0x0000FF00)>>8); 
byte_array[3] = (char)(a & 0x000000FF); 

和解码将

uint32_t a = 0; 
a |= byte_array[1]<<16; 
a |= byte_array[2]<<8; 
a |= byte_array[3]; 
+0

呃 - 这个例子太多错了。 1.如果你打算使用网络翻译例程(htonl()和朋友),那么你必须传输整个变量。在一个小端机器上,这个例子将切掉最低有效字节(在这种情况下是0xaa)。 2.如果您要通过自己除去字节进行传输,则不需要使用htonl() - 该函数可确保二进制endian格式与网络格式匹配。删除字节时,您将定义一个endian格式。 – Aaron 2009-11-09 15:12:40

+0

你说得对,我把第一个例子和htonl合并,但是把高位字节和另一个没有htonl但没有高位字节按照问题中的要求。 我会编辑我的答案以删除对htonl的调用。 – Aszarsha 2009-11-09 15:24:08

0

你有什么不会在你拥有了它的方式工作。例如,a是32位,在你的例子中你设置了高位,这意味着你的printf语句不能放入4位数字。 (0xff00ffaa = 4278255530,这是4位以上)我相信它会溢出缓冲区。我相信printf会将其转换并溢出字段,但它取决于当没有足够的缓冲区空间时,编译器/ C如何实现printf函数。

对于您所拥有的printf语句,您可以传入的最大值为4999个字符。同样,在你用3字节长度字段传输数据的例子中,最大长度为999.理论上你的长度可以是1000,如果你在长度上加1,但你声明的缓冲区是1024其中您需要的最大缓冲区长度为1004个字节。

使用ASCII字符确实可以使消息/数据在整个系统中便携,但它会牺牲使用更多带宽/空间和编程时间和精力来从ASCII转换来传输数据。

看起来好像你有一个好主意,但它仍然需要一些工作。

1

也许你需要使用现有的协议进行这项工作,在这种情况下,忽略我的答案。

为什么不使用Google的Protocol Buffers库来完成这项工作?更简单,更灵活,更高效。

0

这可能是最好的使用一些现有的工具。如果你不能 - 你关心字节序

否则,你可以简单地做这样的事情......

unsigned char msg[1024]; 
int writeIndex = 0; 
[...] 
int mynum = 12345; 
memcpy(msg + writeIndex , &mynum, sizeof mynum); 
writeIndex += sizeof mynum; 

和解码

//[...] also declare readIndex; 
memcopy(&mynum, msg + readIndex, sizeof mynum); 
readIndex += sizeof mynum; 
(即这是一个跨平台的协议?)

(你可以用无符号字符指针代替msg + index的概念,尽管这不太可能)。

像这样使用memcpy可能会更慢,但也更具可读性。如果有必要,您可以在#define或inline函数中实现memcopy克隆 - 毕竟,这只是一个短暂的分配循环。

0

使用atoi函数只有在您希望解码的字符串由您自己的代码构建并且不超过上述几行时才是正确的。也就是说,它只能用于草图代码。

否则,特别是在您的情况下,当数据从网络到达时,atoi函数不能有意义地用于执行解码,因为它没有提供可用的错误处理机制,并且绝对没有防止溢出(未定义的溢出行为)的保护。可以有效用于字符串到整数转换的唯一函数是strto...组的一个函数,您的情况为strtol