2009-02-08 30 views
8

Hey guys, câu hỏi từ một newbie C/Mạng ...trật tự Byte với một mảng lớn các ký tự trong C

tôi đang làm một số lập trình socket trong C và cố gắng vật lộn với vấn đề thứ tự byte. Yêu cầu của tôi (gửi) là tốt nhưng khi tôi nhận được dữ liệu byte của tôi là tất cả ra khỏi trật tự. Tôi bắt đầu với một cái gì đó như thế này ...

char * aResponse= (char *)malloc(512); 
int total = recv(sock, aResponse, 511, 0); 

Khi xử lý câu trả lời này, mỗi từ 16 bit dường như đã đảo ngược byte (tôi đang sử dụng UDP). Tôi cố gắng để khắc phục điều đó bằng cách làm một cái gì đó như thế này ...

unsigned short * _netOrder= (unsigned short *)aResponse; 
    unsigned short * newhostOrder= (unsigned short *)malloc(total); 
    for (i = 0; i < total; ++i) 
    { 
     newhostOrder[i] = ntohs(_netOrder[i]); 
    } 

này hoạt động ok khi tôi đang điều trị các dữ liệu như một đoạn ngắn, tuy nhiên nếu tôi đúc con trỏ đến một char lại các byte được đảo ngược. Tôi đang làm gì sai?

Cảm ơn!

Trả lời

10

Ok, có vẻ là vấn đề với những gì bạn đang làm trên hai cấp độ khác nhau. Một phần của sự nhầm lẫn ở đây dường như bắt nguồn từ việc sử dụng con trỏ của bạn, loại đối tượng mà chúng trỏ tới, và sau đó là cách giải thích mã hóa của các giá trị trong bộ nhớ được trỏ tới bởi (các) con trỏ.

Mã hóa các thực thể nhiều byte trong bộ nhớ là những gì được gọi là endianess.Hai mã hóa phổ biến được gọi là Little Endian (LE) và Big Endian (BE). Với LE, một số lượng 16 bit giống như một đoạn ngắn được mã hóa ít nhất là byte (LSB) đầu tiên. Theo BE, byte quan trọng nhất (MSB) được mã hóa trước tiên.

Theo quy ước, các giao thức mạng thường mã hóa mọi thứ thành thứ gọi là "thứ tự byte mạng" (NBO) cũng giống như BE. Nếu bạn đang gửi và nhận bộ nhớ đệm trên nền tảng cuối lớn, thì bạn sẽ không gặp phải vấn đề chuyển đổi. Tuy nhiên, mã của bạn sẽ là nền tảng phụ thuộc vào quy ước BE. Nếu bạn muốn viết mã di động hoạt động chính xác trên cả hai nền tảng LE và BE, bạn không nên thừa nhận nền tảng cuối cùng của nền tảng.

Đạt di endian là mục đích của thói quen như ntohs(), ntohl(), htons()htonl(). Những chức năng/macro được định nghĩa trên một nền tảng cho thực hiện chuyển đổi cần thiết ở hai đầu gửi và nhận:

  • htons() - Chuyển đổi giá trị ngắn từ trật tự chủ để tự mạng (gửi)
  • htonl() - Chuyển đổi giá trị lâu từ tự chủ để tự mạng (gửi)
  • ntohs() - Côn giá trị ngắn vert từ trật tự mạng để lưu trữ theo thứ tự (sau khi nhận được)
  • ntohl() - Chuyển đổi giá trị lâu từ trật tự mạng để lưu trữ theo thứ tự (sau khi nhận được)

Hiểu rằng nhận xét của bạn về truy cập bộ nhớ khi truyền trở lại ký tự không ảnh hưởng đến thứ tự thực tế của các thực thể trong bộ nhớ. Tức là, nếu bạn truy cập bộ đệm dưới dạng một chuỗi byte, bạn sẽ thấy các byte theo thứ tự bất kỳ mà chúng thực sự được mã hóa thành bộ nhớ, cho dù bạn có máy BE hay LE. Vì vậy, nếu bạn đang xem xét một bộ đệm mã hóa NBO sau khi nhận được, MSB sẽ là đầu tiên - luôn luôn. Nếu bạn nhìn vào bộ đệm đầu ra sau khi bạn đã chuyển đổi trở lại thứ tự máy chủ, nếu bạn có BE máy, thứ tự byte sẽ không thay đổi. Ngược lại, trên một máy LE, các byte sẽ được đảo ngược trong bộ đệm đã chuyển đổi.

Cuối cùng, trong vòng chuyển đổi của bạn, biến total đề cập đến byte. Tuy nhiên, bạn đang truy cập bộ đệm dưới dạng shorts. bảo vệ vòng lặp của bạn không nên total, nhưng nên là:

total/sizeof(unsigned short)

vào tài khoản cho byte kép tự nhiên của mỗi short.

0

thứ tự byte mạng là kết thúc lớn, vì vậy bạn cần phải chuyển đổi thành số cuối nếu bạn muốn nó có ý nghĩa, nhưng nếu nó chỉ là mảng thì không nên gây phiền phức, người gửi gửi nó như thế nào dữ liệu ?

+0

Không, không * chuyển đổi thành ít người dùng cuối, chuyển đổi sang đơn đặt hàng địa phương của máy chủ nếu bạn muốn chương trình của mình di động (OP thậm chí không nói nền tảng của mình là gì). Đó chính xác là những gì ntohs() và ntohl() dành cho. – bortzmeyer

3

Điều này hoạt động tốt khi tôi xử lý dữ liệu dưới dạng ngắn, tuy nhiên nếu tôi chuyển con trỏ đến một thẻ một lần nữa thì các byte được đảo ngược.

Đó là những gì tôi mong đợi.

Tôi đang làm gì sai?

Bạn phải biết người gửi đã gửi: biết liệu dữ liệu có phải là byte (không cần đảo ngược) hay quần short hoặc thời gian dài (thực hiện).

Google cho hướng dẫn được liên kết với các API ntohs, htonshtons.

2

Không rõ ràng những gì aResponse đại diện cho (chuỗi ký tự? Struct?). Endianness chỉ liên quan đến giá trị số, không phải là char s. Bạn cũng cần đảm bảo rằng ở phía người gửi, tất cả các giá trị số được chuyển đổi từ máy chủ sang thứ tự byte mạng (hton*).

1

Ngoài câu hỏi ban đầu của bạn (mà tôi cho là đã được trả lời), bạn nên xem câu hỏi malloc của mình. malloc phân bổ các byte và một đoạn ngắn chưa ký có nhiều khả năng là hai byte.

tuyên bố của bạn sẽ giống như thế:

unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short)); 
+0

Không, 'tổng số' đã được tính theo byte, do đó không cần nhân với 2. Tuy nhiên, OP phải lặp lại từ 0 đến tổng/2, không phải từ 0 đến tổng. –

+0

Có bạn đã đúng. Xấu của tôi ... Chiều chủ nhật muộn :-) –

0

Đối với một byte, chúng tôi có thể không quan tâm đến thứ tự byte.

Các vấn đề liên quan