- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想不通。当我运行我的代码时......即使我绑定(bind)成功,我也会看到来自所有以太网类型和所有接口(interface)的数据。运行几分钟后……它会自行修复。然后我只从一个特定的接口(interface)看到,并且只有当 Ether 类型匹配时。目标是循环遍历所有接口(interface)以查找特定的 MAC 地址。当返回正确的响应时...我们会退出 for 循环,并根据需要配置所有内容。
// Copyright (c) 2017 Keith M. Bradley
//
//
// History:
// 13 May 2017 Keith M. Bradley Creation
// all rights reserved.
//
/* ----------------------- Standard includes --------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netdb.h>
#define SIGNAL_THREAD_KILL 0xFF
#define SIGNAL_THREAD_RESET 0xFE
// Ethernet II protocol to use (0x88b5 ... experimental #1).
#define eType 0x88b5
#define msg_Hello "MikiePLC"
#define msg_Reply "IOM_1.0"
#define msg_Ack "ackMikiePLC"
void* PLCThread(void* arg)
{
// get our pointer to the PLC struct
PLC *myPLC = arg;
// get and save our thread ID
myPLC->tid = pthread_self();
// thread index number?
//------------------------------------------------------------------------------------------------------------------
// locals
uint8_t i; // used as an index or loop counts.
uint8_t j; // used as 2nd index or loop counts.
int rtn; // temp store or function return values.
//------------------------------------------------------------------------------------------------------------------
// create Ethernet buffers and variables.
char* outBuff = NULL; // character buffer for sending out on Ethernet.
size_t outBuffSz = 1540;
char* inBuff = NULL; // character buffer for receiving in on Ethernet.
size_t inBuffSz = 1540;
int fd; // file descriptor for socket.
int flags; // socket flags used bt fcntl().
struct
ifreq ifr; // used to get and set interface parameters.
struct
sockaddr_ll IOM_sa_flt; // socket address struct, used to filter received Ethernet frames from the remote IO module ... used by bind().
struct
sockaddr_ll IOM_sa_rcv; // socket address struct, used to store addr details of received frame ... used by recvfrom().
socklen_t IOM_sa_len; // IOM_sa_rcv length.
fd_set myfds; // used by select().
struct
timeval rcv_tm_out; // time out for select() to declare communications failed.
//------------------------------------------------------------------------------------------------------------------
// initialize Ethernet buffers and variables.
// allocate memory for the Ethernet sending message buffer.
outBuff = malloc(outBuffSz);
if (outBuff == NULL)
printf("\nNATIVE-PLCThread: Could not allocate outBuff memory.");
memset(outBuff, '\0', outBuffSz);
// allocate memory for the Ethernet recevied message buffer.
inBuff = malloc(inBuffSz);
if (inBuff == NULL)
printf("\nNATIVE-PLCThread: Could not allocate inBuff memory.");
// clear the sockaddr_ll structs.
// (send was already cleared ... it is inside the PLC typdef).
memset(&IOM_sa_rcv, 0, sizeof(IOM_sa_rcv));
memset(&IOM_sa_flt, 0, sizeof(IOM_sa_flt));
// set receiving sockaddr_ll struct size.
IOM_sa_len = sizeof(IOM_sa_rcv);
// setup the sending, receiving, and filtering sockaddr_ll's.
myPLC->IOM_sa_snd.sll_family = AF_PACKET;
myPLC->IOM_sa_snd.sll_protocol = htons(eType);
IOM_sa_rcv.sll_family = AF_PACKET;
IOM_sa_rcv.sll_protocol = htons(eType);
IOM_sa_flt.sll_family = AF_PACKET;
IOM_sa_flt.sll_protocol = htons(eType);
//------------------------------------------------------------------------------------------------------------------
// open our socket in dgram mode and setup the socket's features.
fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
if (fd == -1)
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: socket() failed !! - ");
}
// get the socket file descriptor flags.
flags = fcntl(fd, F_GETFL, 0);
// if succesful, set to non-blocking.
if (flags != -1)
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
if (fd != -1) // valid socket file descriptor means ok to proceed with IOM_Addr_search.
{
// IOM_MAC_search
// if MAC_Addr is configured,
// loop to find which interface has the IOM (I/O Module).
//
// begin for loop ----------------------------------------------------------------------------------------------
for (i = 1; 1; i++)
{
// we need to test for thread kill signal.
if((myPLC->ThreadCtrl == SIGNAL_THREAD_KILL) || (myPLC->ThreadCtrl == SIGNAL_THREAD_RESET)) break;
// if the user cleared the MAC addr while we were searching ... give up and run the engine.
if (myPLC->MAC_is_Valid != 0xa5) break;
// clear the ifreq struct.
memset(&ifr, 0, sizeof(ifr));
// i is our 'for' loop counter and our current interface index.
ifr.ifr_ifindex = i;
// does the interface exist?
if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
{
// if not, we ran past top of network interfaces.
printf("\nNATIVE-PLCThread: IOM_MAC_search MAC address not found after searching all interfaces !!!\n");
printf("\n_________________________________________________________________________________________\n");
sleep(10);
i = 0;
continue;
}
// don't mess with loopback interface.
if (strcmp(ifr.ifr_name,"lo") == 0) continue;
// store the ifname using the pointer.
strncpy (myPLC->ifName, ifr.ifr_name, sizeof(ifr.ifr_name) - 1);
myPLC->ifName[IFNAMSIZ - 1] = '\0';
// update the interface index in all sockaddr structs.
myPLC->IOM_sa_snd.sll_ifindex = i;
IOM_sa_rcv.sll_ifindex = i;
IOM_sa_flt.sll_ifindex = i;
// is the interface up?
ioctl(fd, SIOCGIFFLAGS, &ifr);
if ((ifr.ifr_flags & IFF_UP) == 0)
{
printf("\nNATIVE-PLCThread: IOM_Addr_search interface %s (index %d) is down.\n", myPLC->ifName, i);
continue;
}
// bind it.
if (bind(fd, (struct sockaddr*)&IOM_sa_flt, sizeof(IOM_sa_flt)) == -1)
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: IOM_Addr_search bind() failed !!!\n");
continue;
}
// pause and flush? (didn't help at all)
sleep(2);
recvfrom(fd, inBuff, inBuffSz, 0, (struct sockaddr *)&IOM_sa_rcv, &IOM_sa_len);
// fill outBuff with the hello message.
strcpy(outBuff, msg_Hello);
// send hello msg to the IOM with configured IOM_MAC_address.
if (sendto(fd, outBuff, sizeof(msg_Hello), 0, (struct sockaddr *)&(myPLC->IOM_sa_snd), sizeof (myPLC->IOM_sa_snd)) == -1)
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: IOM_Addr_search sendto() failed on interface %s (index %d) !!!\n", myPLC->ifName, i);
continue;
}
// setup for the select() time out loop.
rcv_tm_out.tv_sec = 0;
rcv_tm_out.tv_usec = 50000;
// begin while loop ------------------------------------------------------------------------------------------
//
// select() time out loop.
// wait for valid response from IOM_MAC_address (discard any ETHERNET 2 messages from other MAC's).
//
while ((rcv_tm_out.tv_sec != 0) || (rcv_tm_out.tv_usec != 0))
{
// create the file descriptor set for use by select().
FD_ZERO(&myfds);
FD_SET(fd, &myfds);
// select() to sleep until received frame is ready, or the maximum length of time it would taked to get a response is exceeded.
rtn = select(fd + 1, &myfds, NULL, NULL, &rcv_tm_out);
if (rtn < 0)
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned <0 on interface %s (index %d).\n", myPLC->ifName, i);
break;
}
// did we time out? ... then goto the next interface to search.
else if (rtn == 0)
{
printf("\nNATIVE-PLCThread: IOM_Addr_search select() timed out (returned 0) on interface %s (index %d).\n", myPLC->ifName, i);
break;
}
else // select() returned > 0.
{
if (FD_ISSET(fd, &myfds))
{
// our socket is ready for reading ... 1st clear the buffer and the sock addr.
memset(inBuff, '\0', inBuffSz);
for (j = 0; j < 6; j++)
IOM_sa_rcv.sll_addr[j] = 0;
rtn = recvfrom(fd, inBuff, inBuffSz, 0, (struct sockaddr *)&IOM_sa_rcv, &IOM_sa_len);
if(rtn < 0)
{
if (errno == EAGAIN)
printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned EAGAIN.\n");
else if (errno == EWOULDBLOCK)
printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned EWOULDBLOCK.\n");
else
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned unrecoverable error.\n");
}
break;
}
else if (rtn == 0)
printf("\nNATIVE-PLCThread: IOM_Addr_search a_file_descriptor_is_set yet recvfrom() returned zero.\n");
else // recvfrom() returned > 0.
{
printf("\nNATIVE-PLCThread: IOM_Addr_search recvfrom() returned %d bytes on %s (index %d) MAC %02x:%02x:%02x:%02x:%02x:%02x rcv_tm_out.tv_sec = %d.%d\n",
rtn,
myPLC->ifName,
i,
IOM_sa_rcv.sll_addr[0],
IOM_sa_rcv.sll_addr[1],
IOM_sa_rcv.sll_addr[2],
IOM_sa_rcv.sll_addr[3],
IOM_sa_rcv.sll_addr[4],
IOM_sa_rcv.sll_addr[5],
(int)rcv_tm_out.tv_sec,
(int)rcv_tm_out.tv_usec);
// check the IOM_sa_rcv.MAC_Addr ... is it who we want to talk to? ... if not discard.
for (j = 0; j < 6; ++j)
if ((myPLC->IOM_sa_snd.sll_addr[j]) == (IOM_sa_rcv.sll_addr[j])) continue;
// MAC addr matches?
if (j > 50) // set to 50 to debug ... should be 5.
{
printf("\nMAC Addr from our IOM.\n");
// parse the received response to our hello msg.
if (strcmp(inBuff, msg_Reply) == 0)
{
// fill outBuff with the Ack message.
strcpy(outBuff, msg_Ack);
// send ack message to the IOM with configured IOM_MAC_address.
if (sendto(fd, outBuff, sizeof("ackMikiePLC"), 0, (struct sockaddr *)&(myPLC->IOM_sa_snd), sizeof (myPLC->IOM_sa_snd)) == -1)
{
fprintf(stderr, "%s\n", strerror(errno));
printf("\nNATIVE-PLCThread: IOM_Addr_search sendto() failed on interface %s (index %d) !!!\n", myPLC->ifName, i);
continue;
}
else
{
// declare ComStatus ok.
myPLC->ComStatus = 0xa5;
break; // we have a winner !!!
}
}
else
{
// declare ComStatus still NOT ok.
myPLC->ComStatus = 0x5a;
continue;
}
}
else
{
printf("\nMAC Addr from a stranger (discarded)!!!\n");
break;
}
}// END recvfrom() returned > 0.
}// END if (FD_ISSET(fd, &myfds))
else printf("\nNATIVE-PLCThread: IOM_Addr_search select() returned > 0 yet our only file descriptor was not set !!!\n");
}// END select() returned > 0.
}// END while loop -------------------------------------------------------------------------------------------
if (myPLC->ComStatus == 0xa5) break; // search is done ... break out of for loop.
}// END for loop -----------------------------------------------------------------------------------------------
}// END "valid socket fd means ok to proceed" ----------------------------------------------------------------------
else printf("\nNATIVE-PLCThread: IOM_Addr_search socket() previously failed ... search cannot proceed.\n");
// MAIN ENGINE LOOP !!!---------------------------------------------------------------------------------------------
//
// Loop for the life of this Sedona PLC object (unless Enable is false).
//
while((myPLC->ThreadCtrl != SIGNAL_THREAD_KILL) && (myPLC->ThreadCtrl != SIGNAL_THREAD_RESET))
{
}
CleanExit: //--------------------------------------------------------------------------------------------------------
close(fd);
free(outBuff);
free(inBuff);
free(myPLC);
pthread_exit(NULL);
}
这是启动时的打印示例:
NATIVE-PLCThread:IOM_Addr_search recvfrom() 在 eth0(索引 2)MAC 00:1e:c9:7d:c4:36 rcv_tm_out.tv_sec = 0.49997 上返回 104 个字节
来自陌生人的 MAC 地址!!!
NATIVE-PLCThread:IOM_Addr_search recvfrom() 在 enp1s0(索引 3)MAC 00:1e:c9:7d:c4:36 rcv_tm_out.tv_sec = 0.49998 上返回 152 个字节
来自陌生人的 MAC 地址!!!
NATIVE-PLCThread:搜索所有接口(interface)后未找到 IOM_MAC_search MAC 地址!!!
我应该在 eth0 上看到“select() 超时”,因为以太类型 0x88b5 没有任何响应。
最佳答案
我想我看到了问题。
我用 ETH_P_ALL 创建了套接字。我假设我可以像文档所说的那样在绑定(bind)中更具体。
到目前为止的初步测试没有重现这个问题。
我看到很多消息来源说可以做我最初做的事情...所以这可能是 Linux 或驱动程序中的错误?
关于c - AF_PACKET 套接字上的 Bind() 首先失败......然后自行修复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46551158/
我不知道该怎么做... function f1() { var x = 10; function f2(fx) { var x; x = 6;
早期绑定(bind)和后期绑定(bind)有什么区别? 最佳答案 简短的回答是,早期(或静态)绑定(bind)是指编译时绑定(bind),后期(或动态)绑定(bind)是指运行时绑定(bind)(例如
如何在 SwiftUI View 上使用 Binding(get: { }, set: { }) 自定义绑定(bind)与 @Binding 属性。我已成功使用此自定义绑定(bind)与 @State
我经常发现自己遇到问题,即控件的两个(相关)值被更新,并且两者都会触发昂贵的操作,或者控件可能会暂时处于不一致的状态。 例如,考虑一个数据绑定(bind),其中两个值 (x,y) 相互减去,最终结果用
我想通过我的 ViewModel 控制我的一个窗口的高度和宽度。 这看起来很简单。 但没有。它不起作用。 它检查 ViewModel 的 Width但不是 Height . 奇怪的是,如果我切换 W
UI5中一次性绑定(bind)和单向绑定(bind)有什么区别? 是否有任何用户特定的用例我会使用它们? 我无法从文档中获得太多信息。 最佳答案 单程 它的作用:单向数据流。模型数据的变化(例如通过
(define make (lambda (x) (lambda (y) (cons x (list y))))) (let ((x 7) (p (make 4))) (cons
尽管我或多或少地了解什么是语言绑定(bind),但我很难理解它们是如何工作的。 例如,谁能解释一下如何为 WinAPI 制作 Java 绑定(bind)? 最佳答案 如果您搜索 Foreign Fun
谁能解释为什么我可以重新绑定(bind)列表但不能+? (binding [list vector] (list 1 3)) (binding [list +] (list 1 3)) (bi
我真的很喜欢 Caliburn 和命名约定绑定(bind),我很惊讶 可见性与“CanNAME”约定用于保护 Action 的方式不同。 据我所知, BooleanToVisibilityConver
我了解动态绑定(bind)的实现方式以及静态绑定(bind)和动态绑定(bind)之间的区别,但我只是无法理解动态绑定(bind)的定义。基本上它是一种运行时绑定(bind)类型。 最佳答案 基本上,
http://jsfiddle.net/3NRsd/ var foo = $("div").bind("click", function() { $("div").animate({"hei
这个问题我快疯了...我有一个用户控件,它有一个用于插入操作的 FormView 和一个用于所有其他操作的 GridView。 在这两个控件中,我都有一个 DropDownList,如下所示: '
我有一个绑定(bind)到 ListBox 的地址的 ObservableCollection。然后在 ItemTemplate 中,我使用 {Binding .} 绑定(bind)到当前地址记录。这
如果我有以下简单的 js/knockout 代码: .js( View 模型): var image = ko.observable('http://placehold.it/300x150'); 看
我正在 aurelia 上开发一个自定义属性,让用户在输入文本区域时从列表中进行选择。例如,用法将是这样的: 正如您可能注意到的,auto-complete是属性。现在,当我想显示提示时,我想在自定
我正在使用 EventEmitter2作为我的应用程序内部的消息总线。现在我需要绑定(bind)和取消绑定(bind)一些事件处理程序。因为我也希望他们bind将它们添加到给定的上下文中,我最终得到以
我有以下函数调用: $(".selector").on("click", callback.bind(this, param1, param2)); 在我的回调函数中,我想使用绑定(bind)的 th
我目前正在试验新的编译绑定(bind),并且(再次)达到了我在拼图中遗漏了一个小问题:为什么我必须调用 Bindings.Update?直到现在,我还认为实现 INotifyPropertyChang
我正在阅读一本关于编写 JavaScript 框架的书,并找到了这段代码。但是我不明白它是如何工作的,尤其是 bind.bind 的用法?有人知道吗? var bind = Function.prot
我是一名优秀的程序员,十分优秀!