Я работаю с необработанными розетками Ethernet и испытываю странную проблему, когда отправка /send/recv/recv/повторный шаблон может привести к окончательному блокированию вызова recv на неопределенный срок. Class = "Lang-C PrettyPrint-Override">sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
вместе с беспорядочным режимом, установленным в интерфейсе, который я отправляю и получаю.recv/repeat сценарий работает, как и ожидалось, :
У меня есть приложение Ping/Pong, где приложение A работает в поле A и приложении B запускается в поле B. , и коробка A и B подключены друг к другу одним кабелем Ethernet:
app a :
while (1) {
// Send PING + pass sockaddr_ll with interface info
sendto(...);
// Block until PONG is received + logic to ignore irrelevant traffic
recv(...);
}
app b :
while (1) {
// Block until we recv a PING + logic to ignore irrelevant traffic
recv(...);
// Reply with a PONG + pass sockaddr_ll with interface info
sendto(...);
}
< /code>
Как упомянуто, все работает нормально. Проблема возникает при изменении приложения на:
while (1) {
sendto(...); // PING 1
sendto(...); // PING 2
recv(...); // PONG 1
recv(...); // PONG 2?
}
< /code>
Некоторые важные наблюдения: < /p>
[*] Второй вызов к recv < /code> может заблокировать неопределенное время. Чем больше вы позволяете ему цикть, тем больше вероятность, что это произойдет, но обычно происходит в течение первых 10-20 итераций. < /P>
< /li>
Я думал это Может быть просто плохим кодом, но если я контролирую интерфейс в поле A с TCPDUMP, даже TCPDUMP не сообщит о виде кадра на интерфейсе. После ожидания несколько секунд и нажатия Ctrl+C в приложении A, запущенном ifconfig сообщит о новой упавшей кадре на интерфейсе.
< li> Я знаю, что коробка B отвечает на Pong, потому что я использовал оборудование для мониторинга сети, чтобы отразить ответы от B -> A в отдельную коробку C, и TCPDUMP, работающий в отчетах C, видя Pong. < /P>
< /li>
Если я заменяю приложение A, чтобы запустить в поле B и приложение B, чтобы запустить в поле A, такая же проблема все еще возникает, поэтому Я не думаю (?) Это просто проблема с коробкой a. второй recv и я Используйте отдельную программу, чтобы отправить любую произвольную непонгскую кадр на том же интерфейсе, и через провод, на котором приложение A+B общается, а затем «начнет», что окончательный донг и приложение A прекратит блокировать recv . Я могу сделать это из любой коробки A или коробки B, пока он отправляется на интерфейс субъекта, и он все равно будет «выбить» его. Это просто нужен трафик, чтобы протолкнуть его. Интерфейс, но в конечном итоге снова застрянет. > Просто приложение A , Отправка этих первоначальных "Ping" S будет «пнуть» интерфейса, и первый поин, который он получает > Скорость отправки может иметь какое -то отношение к этому. Если я удаляю петлю и просто повторно заполняю приложение вручную, это не произойдет (или я еще не был свидетелем этого), поэтому у меня есть это на петле. Но логически, что когда -нибудь должно быть только 2 кадра, ожидающих за провод за раз? Что касается того, что я здесь свидетелем? Похоже, ядро или даже Ник просто держатся за кадр и не отпускают, пока что -то еще за ним не пройдет? Я не думаю, что это может быть алгоритм Nagle, потому что я имею дело с необработанными рамами Ethernet, а не TCP. Тот факт, что даже TCPDUMP не сообщает, что видение потерянного кадры - это ошеломляющий. < /P>
это плохая версия ядра? Плохие NIC на обеих коробках (см. Точка 4)? Как я могу отладить это дальше? Вам нужно будет включить беспорядочный режим самостоятельно, запустив Sudo IP -ссылки SET SET DEV romisc on .
"Приложение A" эквивалентно sudo ./app Ping и «App B» эквивалентно sudo ./app pong .
Приложение A (Ping Side) должен print Ping ping pong pong многократно, а приложение b (pong side) должно печатать ping pong многократно. Вместо этого, что я видел в приложении A просто Ping ping pong * silence *.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PING "PING"
#define PONG "PONG"
// To send full PXNG + null terminator
#define DATALEN 5
#define min(x, y) (x > y ? y : x)
// Send a PING or a PONG (whichever `data` is)
int32_t tx_pxng(char *data, size_t len, int32_t sock, struct sockaddr_ll *sockaddr)
{
if (sendto(sock, data, len, 0, (struct sockaddr *)sockaddr, sizeof(*sockaddr)) < 0)
return -1;
// Acknowledge send
if (len > ETH_HLEN)
printf("%s\n", data + ETH_HLEN);
return 0;
}
// Wait for a PING or a PONG (whichever `data` is)
int32_t rx_pxng(char *data, size_t len, int32_t sock, char *buf, size_t buf_len)
{
int32_t read;
rx:
if ((read = recv(sock, buf, buf_len, 0)) < 0)
return -1;
// Filter out irrelevant traffic
if (read < ETH_HLEN || memcmp(data, buf + ETH_HLEN, min((size_t)read - ETH_HLEN, len)) != 0)
goto rx;
// Acknowledge receive
printf("%s\n", data);
return 0;
}
int32_t main(int32_t argc, char *argv[])
{
char *iface_name = NULL;
bool ping_side = false;
int32_t index, sock, send_len = ETH_HLEN + DATALEN;
struct sockaddr_ll sockaddr = {0};
char recv_buf[ETH_FRAME_LEN] = {0}, send_payload[ETH_HLEN + DATALEN] = {0};
if (argc < 3)
{
printf("Usage: pingpong -i [-a|-b]");
return EXIT_FAILURE;
}
iface_name = argv[1];
ping_side = strncmp(argv[2], "ping", 4) == 0;
// Init boilerplate
if ((index = if_nametoindex(iface_name)) < 0)
return EXIT_FAILURE;
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(ETH_P_ALL);
sockaddr.sll_ifindex = index;
if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
return EXIT_FAILURE;
memcpy(send_payload + ETH_HLEN, ping_side ? PING : PONG, DATALEN);
// Main loop
if (ping_side)
{
// "App A"
while (1)
{
// Send PING 1
if (tx_pxng(send_payload, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;
// Send PING 2
if (tx_pxng(send_payload, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;
// Wait for PONG 1
if (rx_pxng(PONG, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;
// Wait for PONG 2 - May block indefinitely???
// Even tcpdump sees nothing...
if (rx_pxng(PONG, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;
}
}
else
{
// "App B"
while (1)
{
// Expect a PING
if (rx_pxng(PING, DATALEN, sock, recv_buf, ETH_FRAME_LEN) < 0)
return EXIT_FAILURE;
// Reply with PONG
if (tx_pxng(send_payload, send_len, sock, &sockaddr) < 0)
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Подробнее здесь: https://stackoverflow.com/questions/794 ... ta-pending
Сырые блоки гнезда Ethernet на вызове RecV с данными, ожидающими [закрыто] ⇐ Linux
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Сырые блоки гнезда Ethernet на вызове RecV с данными, ожидающими [закрыто]
Anonymous » » в форуме Linux - 0 Ответы
- 21 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как запрашивать и находить сырые данные во многих-ко-многим в сводной таблице
Anonymous » » в форуме Php - 0 Ответы
- 15 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как запрашивать и находить сырые данные во многих-ко-многим в сводной таблице
Anonymous » » в форуме Php - 0 Ответы
- 17 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как запрашивать и находить сырые данные во многих-ко-многим в сводной таблице
Anonymous » » в форуме Php - 0 Ответы
- 17 Просмотры
-
Последнее сообщение Anonymous
-