我想通过 UDP 发送一个字符串:
"Jane Doe"
到内网 ip 192.168.0.4
到端口 9000
。我已经通过 Java 的 UDP 和 TCP 完成了很多次,但现在我必须使用标准 C++ 库来完成此操作,并且我找不到任何示例,只有人们无法使其工作的主题。
我知道我必须将
"Jane Doe"
编码为字节数组,然后打开套接字,将其打包在数据报中并发送。
C++ 不是我的母语,这是我无法理解的一小部分代码,我选择了 UDP,因为它总是比 TCP 简单得多。
网络编程的一个很好的来源是Beej 的网络编程指南。下面是一些 Unix 代码示例。
如果这是 Windows 编程:
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;
}
如果您愿意使用 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();
我重写了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;
}
对于 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;
}
对于需要 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