c - Linux sendto 实现可能会向 UDP 消息添加额外的填充

标签 c linux udp porting sendto

我最近使用Windows/Winsock2写了一个C程序,其中要通过UDP传输一个字符串。以下代码产生预期的正确结果:

static const char *network_config_init = "HF-A11ASSISTHREAD";

void send_broadcast_message(){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);


    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

运行此代码会为此调用 sendto 生成以下 wireshark 输出:

    Frame 81421: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface 0
81421   20451.695078000 EWGECO028.local 255.255.255.255 UDP 59  Source port: 51488  Destination port: 48899
Ethernet II, Src: 70:18:8b:c6:5b:f8 (70:18:8b:c6:5b:f8), Dst: ff:ff:ff:ff:ff:ff (ff:ff:ff:ff:ff:ff)
Internet Protocol Version 4, Src: EWGECO028.local (10.10.100.150), Dst: 255.255.255.255 (255.255.255.255)
User Datagram Protocol, Src Port: 51488 (51488), Dst Port: 48899 (48899)
HF-A11ASSISTHREAD <---THIS IS THE TEXT TO BE TRANSMITTED

我现在已经将相同的代码移植到在 VM VirtualBox 上运行的 Ubuntu,并且相同的代码现在通过 wireshark 输出以下内容:

Frame 76620: 60 bytes on wire (480 bits), 60 bytes captured (480 bits) on interface 0
Ethernet II, Src: 08:00:27:d1:97:be (08:00:27:d1:97:be), Dst: ff:ff:ff:ff:ff:ff (ff:ff:ff:ff:ff:ff)
Internet Protocol Version 4, Src: doug-VirtualBox.local (10.0.0.139), Dst: 255.255.255.255 (255.255.255.255)
User Datagram Protocol, Src Port: 39207 (39207), Dst Port: 48899 (48899)
HF-A11ASSISTHREAD. <----NOTE Extra '.'

请注意,在 Windows 中,传输 59 个字节,在 Linux 中,传输 60 个字节。一个额外的 '。'已附加到 Linux 中的消息中。额外的“。”十六进制值为 00。邮件的收件人不接受此额外填充。不能以任何方式更改收件人。

有人知道为什么要在 Linux 中的 UDP 消息中附加一个额外的字节吗?

编辑:这是 Linux 和 Windows 实现的完整代码:

Linux:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

static const int PLUG_PORT = 48899;

static const char *network_config_init = "HF-A11ASSISTHREAD";
static const char *ack = "+ok";
static const char *ssid = "AT+WSSSID=NT_0004A334A523\r";
static const char *sec_settings = "AT+WSKEY=WPA2PSK,AES,dff073ee57cb\r";
static const char *station_mode = "AT+WMODE=STA\r";
static const char *reboot = "AT+Z\r";
static char plug_ip_address[16];

static int m_send_socket;

void send_broadcast_message(){
    printf("message to be sent: %s\n",network_config_init);

    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);

    int config_length = strlen(network_config_init);

    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));

}

void send_message(const char *message){
    printf("message to be sent: %s\n",message);

    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = inet_addr(plug_ip_address);//INADDR_HF-A11ASSISTHREADBROADCAST;//htonl(INADDR_BROADCAST);

    sendto(m_send_socket, message,strlen(message),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

char *receive_message(char *received_message_buffer){
    struct sockaddr_in sender;
    memset((char *)&sender, 0,sizeof(sender));
    sender.sin_family = AF_INET;
    sender.sin_port = htons(PLUG_PORT);
    sender.sin_addr.s_addr = htonl(INADDR_ANY);
    unsigned int sender_size = sizeof(sender);

    assert(sizeof(*received_message_buffer) != 1024);
    memset(received_message_buffer,0,sizeof(*received_message_buffer));
    printf("waiting for reply:\n");
    recvfrom(m_send_socket,received_message_buffer,sizeof(*received_message_buffer),0,(struct sockaddr*)&sender,&sender_size);
    printf("receive result: %s\n",received_message_buffer);
    return received_message_buffer;
}

int main(int argc , char *argv[])
{
    char reply[1024];

    if((m_send_socket = socket(AF_INET , SOCK_DGRAM , 0 )) == -1)
        {
            printf("Could not create send socket\n : %d",m_send_socket);
        }


    int broadcastEnabled=1;

    setsockopt(m_send_socket, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnabled, sizeof(broadcastEnabled));

    //scan for plugs
    send_broadcast_message();

    //get result from listening plugs
    receive_message(reply);

    //get ip address of plug that replied
    memset((char *)plug_ip_address,0,sizeof(plug_ip_address));

    int i = 0;
    while(reply[i] != ','){
        plug_ip_address[i] = reply[i];
        i++;
    }

    //acknowledge connection to plug
    send_message(ack);

    //send SSID of the access point to be connected to
    send_message(ssid);

    receive_message(reply);

    //send security details of the access point to be connected to
    send_message(sec_settings);

    //set the plug back to station mode
    send_message(station_mode);

    receive_message(reply);


    //reboot the plug; it should connect to the given access point after it has booted.
    send_message(reboot);

    close(m_send_socket);

    return 0;
}

window :

#include<stdio.h>
#include<winsock2.h>

static const int PLUG_PORT = 48899;

static const char *network_config_init = "HF-A11ASSISTHREAD";
static const char *ack = "+ok";
static const char *ssid = "AT+WSSSID=NT_0004A334A523\r";
static const char *sec_settings = "AT+WSKEY=WPA2PSK,AES,dff073ee57cb\r";
static const char *station_mode = "AT+WMODE=STA\r";
static const char *reboot = "AT+Z\r";
static char plug_ip_address[16];

static SOCKET m_send_socket;

void send_broadcast_message(){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);


    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

send_message(char *message){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = inet_addr(plug_ip_address);//INADDR_BROADCAST;//htonl(INADDR_BROADCAST);

    sendto(m_send_socket, message,strlen(message),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
    fflush(stdout);
}

char *receive_message(){
    char received_message_buffer[1024];
    struct sockaddr_in sender;
    memset((char *)&sender, 0,sizeof(sender));
    sender.sin_family = AF_INET;
    sender.sin_port = htons(PLUG_PORT);
    sender.sin_addr.s_addr = htonl(INADDR_ANY);
    int sender_size = sizeof(sender);

    memset((char *)received_message_buffer,0,sizeof(received_message_buffer));
    printf("waiting for reply:\n");
    fflush(stdout);
    recvfrom(m_send_socket,received_message_buffer,sizeof(received_message_buffer),0,(struct sockaddr*)&sender,&sender_size);
    printf("receive result: %s\n",received_message_buffer);
    fflush(stdout);
    return received_message_buffer;
}

int main(int argc , char *argv[])
{
    WSADATA wsa;
    struct sockaddr_in local;
    char received_message_buffer[1024];
    char * reply;

    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        return 1;
    }

    if((m_send_socket = socket(PF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
        {
            printf("Could not create send socket : %d" , WSAGetLastError());
        }

    memset((char *)&local,0,sizeof(local));

    int broadcastEnabled=1;

    setsockopt(m_send_socket, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnabled, sizeof(broadcastEnabled));

    //scan for plugs
    send_broadcast_message();

    //get result from listening plugs
    reply = receive_message();

    //get ip address of plug that replied
    memset((char *)plug_ip_address,0,sizeof(plug_ip_address));

    int i = 0;
    while(reply[i] != ','){
        plug_ip_address[i] = reply[i];
        i++;
    }

    //acknowledge connection to plug
    send_message(ack);

    //send SSID of the access point to be connected to
    send_message(ssid);

    reply = receive_message();

    //send security details of the access point to be connected to
    send_message(sec_settings);

    //set the plug back to station mode
    send_message(station_mode);

    reply = receive_message();

    //reboot the plug; it should connect to the given access point after it has booted.
    send_message(reboot);

    closesocket(m_send_socket);
    WSACleanup();
    return 0;
}

谢谢

最佳答案

以太网 II 的最小帧长度在第 2 层为 64 个八位字节,对应于没有 802.1Q 标签的 46 个八位字节的有效载荷大小。 IP header 至少需要 20 个八位字节(无选项),UDP header 需要另外 8 个八位字节,从而给出 18 个八位字节的最大最小有效负载长度。不幸的是,您的负载 "HF-A11ASSISTHREAD" 有 17 个字节长,因此必须对其进行填充。

另见 Removing padding from UDP packets in python (Linux)

关于c - Linux sendto 实现可能会向 UDP 消息添加额外的填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30849655/

相关文章:

linux - 了解 AWK 中的搜索模式?

java - 使用 UDP(数据报)在 Java 中实现 TCP

node.js - 在node.js中发送UDP消息时更改源IP地址

python - 如何连接到 Python 中的 UDP 端口?

c - 服务器客户端消息验证

远程主机上的 C UDP 客户端和服务器

c - 重新启动时如何阻止菜单不受控制地闪烁?

linux - 以 root 身份移动文件,保留所有权 linux

c - 跳过指纹读取器 PAM 模块以从 C 应用程序使用 PAM 进行身份验证

linux - 重新启动后,Hhvm 无法读取任何有意义的 pid 的 pid 文件/var/run/hhvm/pid