如何在C中简单地发送UDP数据?

2w2cym1i  于 2023-11-16  发布在  其他
关注(0)|答案(3)|浏览(170)

我正在努力与UDP套接字。我想基准的时间交换两台机器之间的某种类型的数据。
我很快用C写了这个项目https://github.com/nowox/udp-test,我有一个简单的客户端:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>

#define PORT (3000)

#define SUBIMAGES (1000)
#define FRAMES_PER_SUBIMAGES (23)
#define UDP_FRAME (1442)

#define SERVERADDRESS "127.0.0.1" // 138.131.156.36"

#define BUFFER_SIZE (SUBIMAGES * FRAMES_PER_SUBIMAGES * UDP_FRAME)

char buffer[BUFFER_SIZE];

/**
 * Populate the buffer with random data.
 */
void build(uint8_t* buffer, size_t length)
{
    for (size_t i = 0; i < length; i++)
    {
        buffer[i] = (rand() % 255) + 1;
    }
}

int main(int argc, char **argv)
{
    struct timespec start, end;
    int sockfd;
    struct sockaddr_in server;

    printf("Build Data...\n");
    build(buffer, sizeof(buffer));

    printf("Configure socket...\n");
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        fprintf(stderr, "Error opening socket");
        return EXIT_FAILURE;
    }

    bzero((char*)&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(SERVERADDRESS);
    server.sin_port = htons(PORT);

    printf("Send UDP data...\n");
    clock_gettime(CLOCK_MONOTONIC_RAW, &start);
    for (size_t i = 0; i < BUFFER_SIZE; i += UDP_FRAME)
    {
        if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
                   (const struct sockaddr*)&server, sizeof(server)) < 0)
        {
            fprintf(stderr, "Error in sendto()\n");
            return EXIT_FAILURE;
        }
    }
    clock_gettime(CLOCK_MONOTONIC_RAW, &end);
    uint64_t delta_us = (end.tv_sec - start.tv_sec) * 1000000 +
                        (end.tv_nsec - start.tv_nsec) / 1000;

    printf("Time to send %d subimages: %f[s]\n", SUBIMAGES, delta_us / 1e6f);
    printf("Finished...\n");

    return EXIT_SUCCESS;
}

字符串
我希望看到UDP的嵌入到Wireshark中,但似乎什么也没看到。
第一个问题:为什么我的套接字不发送任何东西?
我发现这是因为WSL(Linux的Windows子系统),所以我转向了Ubuntu
第二个问题:为什么我的服务器没有收到任何信息?

jogvjijk

jogvjijk1#

您正在将客户端绑定到与服务器相同的端口。这是无效的。您不需要绑定客户端。
注解掉客户端的bind调用,数据包将从随机选择的端口发送到服务器。您的服务器将接收它们,但您的服务器中存在另一个退出条件错误,因此在接收帧时添加一些错误,以查看它是否实际发生。

oxcyiej7

oxcyiej72#

wsl无法打开Windows防火墙,数据包丢失。用mingw编译它(添加ws2_32),它将工作

9udxz4iz

9udxz4iz3#

你在接收端尝试过不同的计算机吗?我在CentOS 7.9中遇到了防火墙问题。
如果其他计算机无法接收任何可能是由于发送代码.这里是另一个代码从John Selbie's post与修改为C编程语言.我也使用端口号10102在同一子网.

//
// send_udp.c - send string using UDP
//
//
// How to compile
//     gcc -Wall send_udp.c -o send_udp.out
//         
//
// How to run (after compile)
//     $ ./send_udp.out  Somehow $ bash ./send_udp.sh not working
//
// To do
//     Find where is UDP?
//
// Reference:
//     Code: https://stackoverflow.com/a/24560310/5595995

#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <errno.h>
#include <stdio.h> 
#include <stdlib.h>
// #include <iostream>  // C++

int resolvehelper(
  const char* hostname, 
  int family, 
  const char* service, 
  struct sockaddr_storage* pAddr);

int main()
{
    int result = 0;
    int sock = socket(AF_INET, SOCK_DGRAM, 0);

    char szIP[100];
    char *IP_address = "192.168.3.43";
    char *port_no = "10102"; 

    // zero-int, sin_port is 0, which picks a random port for bind.
    struct sockaddr_in addrListen = {}; 
    addrListen.sin_family = AF_INET;
    result = bind(sock, (struct sockaddr*)&addrListen, sizeof(addrListen));
    if (result == -1)
    {
       int lasterror = errno;
       // std::cout << "error: " << lasterror;
       printf("error: %d\n", lasterror); 
       exit(1);
    }

    struct sockaddr_storage addrDest = {};
    // result = resolvehelper("192.168.0.4", AF_INET, "9000", &addrDest);
    result = resolvehelper(IP_address, AF_INET, port_no, &addrDest);
    if (result != 0)
    {
       int lasterror = errno;
       // std::cout << "error: " << lasterror;
       printf("error: %d\n", lasterror); 
       exit(1);
    }

    const char* msg = "From another computer...";

    size_t msg_length = strlen(msg);

    result = sendto(sock, msg, msg_length, 0, 
        (struct sockaddr*)&addrDest, sizeof(addrDest));

    // std::cout << result << " bytes sent" << std::endl;
    printf("%d bytes sent\n", result);     
    
    return 0;

}

int resolvehelper(
  const char* hostname, 
  int family, 
  const char* service, 
  struct sockaddr_storage* pAddr) {

    int result;
    struct addrinfo* result_list = NULL;
    struct addrinfo hints = {};
    hints.ai_family = family;
    hints.ai_socktype = SOCK_DGRAM; // without this flag, getaddrinfo will return 3x the number of addresses (one for each socket type).
    result = getaddrinfo(hostname, service, &hints, &result_list);
    if (result == 0)
    {
        //ASSERT(result_list->ai_addrlen <= sizeof(sockaddr_in));
        memcpy(pAddr, result_list->ai_addr, result_list->ai_addrlen);
        freeaddrinfo(result_list);
    }

    return result;
}

字符串
这是雷米勒博用C++编程语言编写的接收端代码。你可以找到C版本或转换此片段。

//
//// receive_udp.cpp - receive string using UDP
////
////
//// How to compile
////     g++ -std=c++11 -Wall receive_udp.cpp -o receive_udp.sh
////         c++98 and c++03 will induce error
////
//// How to run (after compile)
//       (1) Modify sending side
//           for example, PORT and host IP address in  send_udp.cpp
//
//       (2) ./receive_udp.sh  Somehow bash ./send_udp.sh not working
//
//  Error
//      Not received at CentOS
//          Possible solution:
//          https://ahelpme.com/linux/multicast/receive-multicast-packets-on-centos-7-and-other-linux-distros/
//          https://unix.stackexchange.com/questions/234834/how-do-i-enable-an-interface-to-listen-to-multicast
//          https://unix.stackexchange.com/a/299197/275019 - It looks like CentOS having configuration in different files
//
// Reference:
//     code: https://stackoverflow.com/a/53054862/5595995

#include <iostream>
#include <string.h>
#include <fstream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

// #define PORT 8080
#define PORT 10102

int main() {
  int serSockDes, readStatus;
  struct sockaddr_in serAddr, cliAddr;
  socklen_t cliAddrLen;
  char buff[2048] = {0};
  char msg[] = "Hello to you too!!!\n";
  int sizeOfrePack = 2048;

  //creating a new server socket

  if ((serSockDes = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket creation error...\n");
    exit(-1);
  }
  else {
    cout << "socket created" << endl;
  }

  //binding the port to ip and port
  serAddr.sin_family = AF_INET;
  serAddr.sin_port = htons(PORT);
  serAddr.sin_addr.s_addr = INADDR_ANY;

  if ((bind(serSockDes, (struct sockaddr*)&serAddr, sizeof(serAddr))) < 0) {
    perror("binding error...\n");
    close(serSockDes);
    exit(-1);
  }
  else {
    cout << "binding" << endl;
  }

  cliAddrLen = sizeof(cliAddr);
  /*
  recvfrom(sockId, rePack, sizeof(rePack), 0, (struct sockaddr *)&raddr, (socklen_t *)&len);
   processPakcet(recv_size)
  */
  readStatus = recvfrom(serSockDes, buff, sizeOfrePack, 0, (struct sockaddr*)&cliAddr, &cliAddrLen);
  if (readStatus < 0) {
    perror("reading error...\n");
    close(serSockDes);
    exit(-1);
  }
  else {
    cout << "reading" << endl;
  }

  cout.write(buff, readStatus);
  cout << endl;

  if ( sendto(serSockDes, msg, strlen(msg), 0, (struct sockaddr*)&cliAddr, cliAddrLen) < 0 ) {
    perror("sending error...\n");
    close(serSockDes);
    exit(-1);
  }
  else {
    cout << "sending" << endl;
  }

  close(serSockDes);

  return 0;
}


工作环境:
操作系统:Ubuntu 18.04
 GCC 7.5
 G++ 5.4

相关问题