我已经设定了编写一些软件来从我们的嵌入式linux设备通信到服务器的任务。我要与之通信的服务器使用严格的协议,协议非常模糊和专有 - 我不想在这里命名,因为信息可能对我工作的公司敏感。
因此,数据必须采用4位半字节(N),32位无符号整数(U),32位有符号整数(S),8位无符号整数(X)和字符(C)的形式。因此,例如,简化的登录结构可以是NNNN-用户ID,其后是XX-一些更多的数据,CCCC访问代码。所以我需要按顺序发送NNNNXXCCCC才能登录。
需要通过UDP发送数据,然后在同一端口上侦听确认。所以我这样做的方式是我编写了一个send_and_receive
函数,然后对结构进行编码,将结构发送到服务器。
typedef u_int8_t NN;
typedef u_int8_t X;
typedef int32_t S;
typedef u_int32_t U;
typedef char C;
#pragma pack(1)
typedef struct{
NN user_id[2];
X some_data[2];
C access_code[4];
} LogOnRequest;
然后我声明并填写结构的信息并使用此函数发送它:
void send_and_receive(void* message, void* reply, int do_send, int expect_reply){
struct sockaddr_in serv_addr;
int sockfd, i, slen=sizeof(serv_addr);
int buflen = BUFLEN;
void* buf = NULL;
if ( (strlen(message)) >= BUFLEN)
err("Message too big");
buf = malloc(buflen);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_aton(IP_ADDRESS, &serv_addr.sin_addr)==0)
err("inet_aton() failed\n");
if(do_send == TRUE){
strcpy(buf, message);
if (sendto(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, slen)==-1)
err("sendto()");
}
if (expect_reply == TRUE){
if (recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
err("recvfrom()");
}
memcpy(reply, buf, BUFLEN);
close(sockfd);
free(buf);
}
现在,当我这样做时,我得不到回复,也没有注意到服务器上已收到数据包。基本上我想知道我是否正确这样做,有更好的方法吗?是否可以使用bash脚本执行相同的操作?
任何反馈都会很棒,因为我对这一点感觉不够深入。
答案 0 :(得分:2)
您需要等待一段时间才能回复。如果没有,则需要重新传输查询并再次等待。 UDP是“尽力而为”的传递服务,没有任何内置的重试。
您还需要确保以与另一端预期相同的方式发送多字节值。哪个字节首先出现?
答案 1 :(得分:2)
在这种情况下,我一如既往地鼓励您使用WireShark或任何其他嗅探器软件。这将解除你在sendto()尝试后发生的所有魔法:字节顺序,应用的实际地址/端口,收到的任何反馈等等。是的,正如@wildplasser在评论中所说,你不应该发送所有的缓冲区。因此,您必须添加“消息大小”作为输入参数。