Bir datagram paketine daha üst düzey dillerde bakmak mümkün mü?

Şu anda datagram (udp) paketlerini bazı yüksek seviyeli dillerle ilgilenen bir c programını çalıştırmaya çalışıyorum. Paketler değişken büyüklükte olabildiğinden, boyutlarını belirten bir tam sayı ile başlarlar. C, MSG_PEEK bayrağı ile bu değeri yalnızca ilk olarak almak için recv çağrısı yaptıktan sonra bir yerleştirme arabelleği ayırın ve paketin geri kalanını okuyun. Kod (basitleştirilmiş) şu şekilde gider:

// Simplified message format.
struct message {
    int length;
    char[] text;
}
struct message *m = malloc (sizeof(int));

// Read out in just length.
recv (sock, m, sizeof(int), MSG_WAITALL | MSG_PEEK);
int txtlen = ntohl (m->length) * sizeof(char);
int msglen = sizeof(int) + txtlen;

// Read complete packet.
m = realloc (m, msglen);
read (sock, m, msglen);
m->text[txtlen] = '\0';

// Show result.
printf("%s\n", &m->text);

Devasa bir arabellek ayırmak ve daha büyük paketlerin gelmeyeceğini umduğum yaygın uygulamalardan kaçınmak istiyorum. Yani datagrama bakmak veya python veya java gibi daha yüksek seviyedeki dillerde mümkün olan en uzunluğunu belirlemek gibi bir şey var mı?

0
Kesinlikle çok liimited kaynakları olan gömülü bir sistem olmadıkça, kesinlikle ..
katma yazar Karoly Horvath, kaynak

3 cevap

Muazzam bir arabellek ayırmak ve görünüşe göre paketin daha büyük olmamasını umarak yaygın bir uygulamadan kaçınmak istiyorum.

Ne demek istediğinden emin değilim. Bir UDP paketi bir kerede gelir, böylece başlangıç ​​tamsayı arabelleğinizin ne kadar büyük olması gerektiğini söyler; o geldikten sonra "büyümek" olmaz.

Boş bir karakter ekledikçe, uzunluk hesaplamanızda bunu hesaba katmanız gerekir:

int msglen = sizeof(int) + txtlen + 1;

realloc() kullandığınızda dikkatli olun:

m = realloc (m, msglen);

realloc başarısız olursa, m değerini sıfırlar. Bu, orijinal olarak kendisine tahsis edilen belleğe ilişkin tek başvurunuzu kaybedeceğiniz anlamına gelir. Bu nedenle, hiçbir zaman free() işlemini yapamazsınız. Böyle bir şey deneyin:

void *tmp = realloc(m, msglen)
if (tmp == null) {
 //handle the error
}
m = tmp;

And when you print the data, m->text evaluates to the address of the first character, so you can use

printf("%s\n", m->text);

Alternatif olarak, yapınızı sabit bir boyutla tanımlayabilirsiniz.

struct message {
  int length;
  char *text;
}

Sonra metin arabelleğinizi (yalnızca) ayırmak için malloc() komutunu kullanabilirsiniz:

struct message m;
recv(sock, &m.length, sizeof(int), MSG_WAITALL | MSG_PEEK);
m.text = malloc(m.length + 1);//+1 for the null that you'll append
read(sock, m.text, m.length);
m.text(m.length) = '\0';

printf("%s\n", m.text);
free(m.text);

Projenizle iyi şanslar - Ağ programlama her zaman bir öğrenme deneyimidir!

1
katma
Yakalama için teşekkürler! Cevabımı düzeltmemde yaptım.
katma yazar Adam Liss, kaynak
Basit tutmak için kod örneğindeki realloc'u kontrol etmekten kaçındım. Yukarıda belirtildiği gibi, iki okuma çağrısı iki paketi okuyacaktır ve bu yüzden bir yapı tercih ettim.
katma yazar XZS, kaynak

UDP datagrams are limited to 64K, then ethernet frames are 1500 bytes (unless your network is using jumbo frames, which could be up to 9000 bytes). Protocol designers usually try to avoid IP fragmentation, so most likely your incoming packets are small, i.e. less then 1500 bytes.

1472 (1500 ethernet çerçeve uzunluğu - 20 bayt IP başlık - 8 bayt UDP başlığı) statik arabelleği ile başlayacağım. Bazı keyfi protokollerle uğraşmak zorunda kalırsanız, bunu 64 K'ya kadar çarpın. Eğer bunu karşılayamıyorsanız - MSG_PEEK ile gerçek boyutları toplayın, uygun bir ortalama bulun ve malloc (3) .

0
katma
Evet, 64K kesinlikle bir israftır, fakat bu gün ve yaşta, gömülü/kaynak kısıtlı bir ortamda olmadıkça, gerçekten bir problem değildir.
katma yazar Nikolai Fetissov, kaynak
64 K limitinin, paket uzunluğunu belirten 16 bit UDP başlık alanından gelmesini bekliyorum. Yani bu gerçekten bir kayıt tamponu için bakım gerekir. Ancak 64K bile, gerekli olan belleğin daha önce sadece int'yi okuyarak daha önce bilinebileceğini göz önünde bulundurarak bir atık.
katma yazar XZS, kaynak

Neden bunu yapmıyorsun?

message = (struct message *)malloc(sizeof(struct message));
read(sock, &message->length, sizeof(int);
message->length = ntohl(message->length);
message->text = (char *)malloc(message->length + 1);
read(sock, message->text, message->length);
message->text[message->length] = 0;
0
katma
Ne yazık ki bu iki datagram aldığından çalışmaz. İlk okuma ile, sadece int'den daha fazlasını içermesine rağmen, tüm datagram atılır.
katma yazar XZS, kaynak