在 C++ 中通过 UDP 发送字符串

问题描述 投票:0回答:5

我想通过 UDP 发送一个字符串:

"Jane Doe"
到内网 ip
192.168.0.4
到端口
9000
。我已经通过 Java 的 UDP 和 TCP 完成了很多次,但现在我必须使用标准 C++ 库来完成此操作,并且我找不到任何示例,只有人们无法使其工作的主题。

我知道我必须将

"Jane Doe"
编码为字节数组,然后打开套接字,将其打包在数据报中并发送。

C++ 不是我的母语,这是我无法理解的一小部分代码,我选择了 UDP,因为它总是比 TCP 简单得多。

c++ sockets udp
5个回答
23
投票

网络编程的一个很好的来源是Beej 的网络编程指南。下面是一些 Unix 代码示例。

如果这是 Windows 编程:

  • “sock”应该是
    SOCKET
    类型,而不是
    int
  • 使用
    closesocket
    代替
    close
  • #include <winsock2.h>
    而不是所有那些 Unix 标头

#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 <stdlib.h>
#include <iostream>


int resolvehelper(const char* hostname, int family, const char* service, sockaddr_storage* pAddr)
{
    int result;
    addrinfo* result_list = NULL;
    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;
}


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

    char szIP[100];

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


    sockaddr_storage addrDest = {};
    result = resolvehelper("192.168.0.4", AF_INET, "9000", &addrDest);
    if (result != 0)
    {
       int lasterror = errno;
       std::cout << "error: " << lasterror;
       exit(1);
    }

    const char* msg = "Jane Doe";
    size_t msg_length = strlen(msg);

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

    std::cout << result << " bytes sent" << std::endl;
    
    return 0;

}


13
投票

如果您愿意使用 boost 库,这很容易做到。

这是代码片段

#include "boost/asio.hpp"
using namespace boost::asio;

...

io_service io_service;
ip::udp::socket socket(io_service);
ip::udp::endpoint remote_endpoint;

socket.open(ip::udp::v4());

remote_endpoint = ip::udp::endpoint(ip::address::from_string("192.168.0.4"), 9000);

boost::system::error_code err;
socket.send_to(buffer("Jane Doe", 8), remote_endpoint, 0, err);

socket.close();

6
投票

我重写了selbie代码,使其更像C++,并且我将其最小化了一点。

#include <iostream>
#include <string>

#include <arpa/inet.h> // htons, inet_addr
#include <netinet/in.h> // sockaddr_in
#include <sys/types.h> // uint16_t
#include <sys/socket.h> // socket, sendto
#include <unistd.h> // close

int main(int argc, char const *argv[])
{
    std::string hostname{"192.168.0.4"};
    uint16_t port = 9000;

    int sock = ::socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in destination;
    destination.sin_family = AF_INET;
    destination.sin_port = htons(port);
    destination.sin_addr.s_addr = inet_addr(hostname.c_str());

    std::string msg = "Jane Doe";
    int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
    std::cout << n_bytes << " bytes sent" << std::endl;
    ::close(sock);

    return 0;
}

0
投票

对于 Windows,我采用了 Mikolasan's 最小化版本的 selbie's 代码,并根据 https://beej.us/guide/bgnet/html/#windows 进行修改,以获得一个小型独立示例。

要编译它,您需要链接 Winsock 库。

#include <iostream>
#include <string>

#include <winsock2.h>

int main()
{
    // Initialise Winsock DLL
    // See https://beej.us/guide/bgnet/html/#windows 
    WSADATA wsaData;      
    // MAKEWORD(1,1) for Winsock 1.1, MAKEWORD(2,0) for Winsock 2.0
    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }
    
    // Set up connection and send 
    std::string hostname{ "192.168.0.4" };
    uint16_t port = 9000;

    SOCKET sock = ::socket(AF_INET, SOCK_DGRAM, 0);
     
    sockaddr_in destination;
    destination.sin_family = AF_INET;
    destination.sin_port = htons(port);
    destination.sin_addr.s_addr = inet_addr(hostname.c_str());

    std::string msg = "Jane Doe";
    int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
    std::cout << n_bytes << " bytes sent" << std::endl;
    ::closesocket(sock);

    // Clean up sockets library
    WSACleanup();

    return 0;

}

0
投票

对于需要 C 编程语言版本的人,我将 [上面 John Celbie 的代码][1] 转换为 C 编程语言。

//
// 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;
}

运行环境:

  操作系统:Ubuntu 18.04 海湾合作委员会 7.5

[1]:https://stackoverflow.com/a/24560310/5595995

© www.soinside.com 2019 - 2024. All rights reserved.