0

我的任务是编写一些软件来从我们的嵌入式 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 脚本做同样的事情?

任何反馈都会很棒,因为我在这方面感觉不够深入。

4

2 回答 2

2

在这种情况下,像往常一样,我想鼓励您使用 WireShark 或任何其他嗅探器软件。这将解密您 sendto() 尝试后发生的所有魔法:字节顺序、应用的实际地址/端口、收到的任何反馈等。是的,正如@wildplasser 在评论中所说,您不应该发送所有缓冲区。所以你必须添加“消息大小”作为输入参数。

于 2013-09-18T21:16:11.537 回答
2

您需要等待一段时间才能得到回复。如果没有得到,则需要重新发送查询并再次等待。UDP 是一种“尽力而为”的交付服务,没有任何内置的重试。

您还需要确保以与另一端期望的方式相同的方式发送多字节值。哪个字节先出现?

于 2013-09-18T20:52:32.303 回答