生のイーサネット フレームを送受信するプロトコルを C で実装しようとしていますが、Linux 環境でpoll()
およびを使用していくつかの問題に遭遇しました。recvfrom()
私の問題はほとんど概念的なものだと思うので、今のところコードを投稿することは避けます。
受信データ用に 2 つのソケットがありpoll()
、いずれかのソケットでデータの準備ができたことを、戻り値と関連するpollfd
構造体の状態を通じて示すために使用されています。私が最初にプログラムを実行したとき、これは今私のために働いています。テストのために、私は ARP フレームのみに関心がありpoll()
、ARP フレームが到着するのを待つために使用できます。到着したらrecvfrom()
、データを処理できる場所にコピーするように呼び出します。これはすべて正常に機能しています。
poll()
問題は、ソケットに新しいデータが到着していない場合でも、ソケットからデータを読み取る準備ができていることを後続の呼び出しが報告し続けることです。ソケットからデータを呼び出して読み取ったら、データの準備ができたことを報告する前に、新しいフレームが到着するまで待ちrecvfrom()
たいと思います。poll()
これまで使用したことがないため、記述子を「クリア」して、新しいフレームが来るまでデータの準備ができていることを報告するのpoll()
をやめる明示的な手順があるかどうかはわかりません。メンバーをクリアしています。を呼び出す前に構造体のpoll()
revents
pollfd
poll()
poll()
revents
私はpoll()
マニュアルページを調べましたが、これに関する情報を見つけることができませんでした。ソケット/ポーリングが高レベルでどのように機能するかを誤解しているように感じるので、助けていただければ幸いです。
[編集] これが私のコードの大部分です。この例のコードは、ソケットを 1 つだけ含めることで単純化しています。これもすべてクラスにカプセル化されて広がっていますが、このように書き直すと私の問題が再現されます。私の最終的なコードには、API 呼び出しのエラー チェックがあり、コンテンツを印刷するだけでなく、受信バッファーをコピーしてフレームを処理しますが、それ以外はほとんど同じです。
#include <stdio.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <poll.h>
#include <linux/if_ether.h>
int main()
{
uint8_t sendBuffer_[1536];
uint8_t receiveBuffer_[1536];
struct pollfd pollStruct[1];
printf("Making socket...");
int mySocket = socket( AF_PACKET, SOCK_RAW, htons(ETH_P_ARP) );
fcntl(mySocket, F_SETFL, O_NONBLOCK);
char *options;
options = "eth0";
setsockopt(mySocket, SOL_SOCKET, SO_BINDTODEVICE, options, 4);
printf("Descriptor: %i\n", mySocket);
while(1)
{
pollStruct[0].fd = mySocket;
pollStruct[0].events = POLLIN;
pollStruct[0].revents = 0;
if( poll(pollStruct, 1, 0) == 1)
{
printf("New Frame Arrived: ");
uint16_t frameLength = recvfrom( mySocket, receiveBuffer_, 1536, 0, NULL, NULL);
printf("Destination MAC: ");
for ( uint8_t i = 0; i < 6; ++i ) {
printf("0x%x ", receiveBuffer_[i]);
}
printf("\nSource MAC: ");
for ( uint8_t i = 0; i < 6; ++i ) {
printf("0x%x ", receiveBuffer_[i + 6]);
}
printf("\nEtherType: ");
for ( uint8_t i = 0; i < 2; ++i ) {
printf("0x%x ", receiveBuffer_[i + 12]);
}
printf("\nPayload: ");
for ( uint32_t i = 14; i < frameLength; ++i ) {
printf("0x%x ", receiveBuffer_[i]);
}
printf("\n");
//Clear buffer
for ( uint32_t i = 0; i < frameLength; ++i )
receiveBuffer_[i] = 0;
}
}
}
最初はこれについて言及しませんでしたが、このコードを Beaglebone Black にデプロイしようとしています。GCC を使用してコンパイルされた Ubuntu の VM でこのプログラムを実行すると、期待どおりに動作します。フレームを受信/印刷した後、プログラムは新しいフレームが到着するまで視覚的にアイドル状態になります。プログラムをクロスコンパイルして実行すると、プログラムは新しいパケットが到着するまで同じパケットを連続して出力します。戻るreceiverBuffer[]
たびにクリアしているので、データを継続的にコピーしているため、バッファにコピーされた後、内部バッファからデータをクリアしていないようです。recvfrom()
recvfrom()