C ++同时接收2个或多个UDP消息
C++ Receiving 2 or more UDP Messages at same time
我正在尝试在我的 main.cxx 中接收 UDP 消息。我创建了一个 UDP 服务器方法 getUdp(char *buffer) 来在我的 while(true) 无限循环中监听传入的 UDP 消息。
这是我面临的问题。此 UDP 服务器能够一次侦听一条消息。当两个或多个 UDP 消息在 相同 时间到达时,它不会排队进入缓冲区。我想是因为socket在死循环中每次调用该方法时,getUdp()方法打开一个socket,获取消息并关闭socket,导致服务器无法对消息进行排队。
我如何调整此代码以接收 2 个或更多 UDP 消息?
感谢任何建议。
谢谢。
UdpServer.cpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#include <time.h>
#include "UdpServer.h"
#include "stdafx.h"
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 4096
void getUDP(char *buffer);
void UDPServer::MyUDP::getUDP(char *buffer)
{
WSADATA w; /* Used to open windows connection */
int client_length; /* Length of client struct */
int bytes_received; /* Bytes received from client */
SOCKET sd; /* Socket descriptor of server */
struct sockaddr_in server; /* Information about the server */
struct sockaddr_in client; /* Information about the client */
struct hostent *hp; /* Information about this computer */
char host_name[256]; /* Name of the server */
time_t current_time; /* Current time */
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
}
/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
}
/* Clear out server struct */
memset((void *)&server, '[=10=]', sizeof(struct sockaddr_in));
/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(11000);
/* Set address automatically if desired */
/* Get host name of this computer */
gethostname(host_name, sizeof(host_name));
hp = gethostbyname(host_name);
/* Check for NULL pointer */
if (hp == NULL)
{
fprintf(stderr, "Could not get host name.\n");
closesocket(sd);
WSACleanup();
}
unsigned int a = 127;
unsigned int b = 0;
unsigned int c = 0;
unsigned int d = 1;
/* Assign the address */
server.sin_addr.S_un.S_un_b.s_b1 = a;
server.sin_addr.S_un.S_un_b.s_b2 = b;
server.sin_addr.S_un.S_un_b.s_b3 = c;
server.sin_addr.S_un.S_un_b.s_b4 = d;
/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Could not bind name to socket.\n");
closesocket(sd);
WSACleanup();
}
/* Print out server information */
printf("Server running on %u.%u.%u.%u\n", (unsigned char)server.sin_addr.S_un.S_un_b.s_b1,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b2,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b3,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b4);
printf("Press CTRL + C to quit\n");
/* Loop and get data from clients */
client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
}
current_time = time(NULL);
closesocket(sd);
WSACleanup();
}
main.cxx
int main(int argc, char** argv)
{
while(true)
{
//! wait for UDP message
UDPServer::MyUDP myudp;
myudp.getUDP(buffer);
if(buffer[0] != 0)
{
string udpMsg(buffer);
if(udpMsg == "ProcessThisMessage")
{
memset(&buffer[0], 0, sizeof(buffer));
cout << "UDP Message: " + udpMsg;
}
...
}
}
}
I figured it is because the socket is everytime the method is called
in the infinite loop, the getUdp() method opens a socket, gets the
message and closes the socket, resulting in the server not being able
to queue the messages.
您的直觉是正确的。当您将 UDP 套接字绑定到端口时,网络堆栈将为您缓冲(有限数量的)传入 UDP 数据包,以便(假设您以相对及时的方式调用 recv()),传入数据包不应该得到丢失。但是当你 closesocket() 套接字时,缓冲区被释放,当然在没有套接字绑定到 UDP 端口并且接收到 UDP 数据包的时候,传入的 UDP 数据包将被简单地丢弃(即根本不会缓冲) 因为没有套接字绑定到该端口。
How am I able to tweak this code to receive 2 or more UDP messages?
Appreciate any advice.
至少在概念上,您需要将 getUdp() 方法分成三个独立的部分:一个 Setup() 部分,您在程序启动时调用一次,一个 Receive() 部分(仅包含recv() 调用),你可以调用任意多次,以接收下一个数据包,最后是一个 Cleanup() 部分,它关闭套接字并关闭 TCP 堆栈(只有当你的程序即将退出)。这样 UDP 套接字在您的程序 运行 的整个过程中保持有效并绑定到端口,因此 OS 将可靠地缓冲传入的 UDP 数据包以通过 recv() 提供给您的程序。
我正在尝试在我的 main.cxx 中接收 UDP 消息。我创建了一个 UDP 服务器方法 getUdp(char *buffer) 来在我的 while(true) 无限循环中监听传入的 UDP 消息。
这是我面临的问题。此 UDP 服务器能够一次侦听一条消息。当两个或多个 UDP 消息在 相同 时间到达时,它不会排队进入缓冲区。我想是因为socket在死循环中每次调用该方法时,getUdp()方法打开一个socket,获取消息并关闭socket,导致服务器无法对消息进行排队。
我如何调整此代码以接收 2 个或更多 UDP 消息? 感谢任何建议。
谢谢。
UdpServer.cpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#include <time.h>
#include "UdpServer.h"
#include "stdafx.h"
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 4096
void getUDP(char *buffer);
void UDPServer::MyUDP::getUDP(char *buffer)
{
WSADATA w; /* Used to open windows connection */
int client_length; /* Length of client struct */
int bytes_received; /* Bytes received from client */
SOCKET sd; /* Socket descriptor of server */
struct sockaddr_in server; /* Information about the server */
struct sockaddr_in client; /* Information about the client */
struct hostent *hp; /* Information about this computer */
char host_name[256]; /* Name of the server */
time_t current_time; /* Current time */
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
}
/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
}
/* Clear out server struct */
memset((void *)&server, '[=10=]', sizeof(struct sockaddr_in));
/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(11000);
/* Set address automatically if desired */
/* Get host name of this computer */
gethostname(host_name, sizeof(host_name));
hp = gethostbyname(host_name);
/* Check for NULL pointer */
if (hp == NULL)
{
fprintf(stderr, "Could not get host name.\n");
closesocket(sd);
WSACleanup();
}
unsigned int a = 127;
unsigned int b = 0;
unsigned int c = 0;
unsigned int d = 1;
/* Assign the address */
server.sin_addr.S_un.S_un_b.s_b1 = a;
server.sin_addr.S_un.S_un_b.s_b2 = b;
server.sin_addr.S_un.S_un_b.s_b3 = c;
server.sin_addr.S_un.S_un_b.s_b4 = d;
/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Could not bind name to socket.\n");
closesocket(sd);
WSACleanup();
}
/* Print out server information */
printf("Server running on %u.%u.%u.%u\n", (unsigned char)server.sin_addr.S_un.S_un_b.s_b1,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b2,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b3,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b4);
printf("Press CTRL + C to quit\n");
/* Loop and get data from clients */
client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
}
current_time = time(NULL);
closesocket(sd);
WSACleanup();
}
main.cxx
int main(int argc, char** argv)
{
while(true)
{
//! wait for UDP message
UDPServer::MyUDP myudp;
myudp.getUDP(buffer);
if(buffer[0] != 0)
{
string udpMsg(buffer);
if(udpMsg == "ProcessThisMessage")
{
memset(&buffer[0], 0, sizeof(buffer));
cout << "UDP Message: " + udpMsg;
}
...
}
}
}
I figured it is because the socket is everytime the method is called in the infinite loop, the getUdp() method opens a socket, gets the message and closes the socket, resulting in the server not being able to queue the messages.
您的直觉是正确的。当您将 UDP 套接字绑定到端口时,网络堆栈将为您缓冲(有限数量的)传入 UDP 数据包,以便(假设您以相对及时的方式调用 recv()),传入数据包不应该得到丢失。但是当你 closesocket() 套接字时,缓冲区被释放,当然在没有套接字绑定到 UDP 端口并且接收到 UDP 数据包的时候,传入的 UDP 数据包将被简单地丢弃(即根本不会缓冲) 因为没有套接字绑定到该端口。
How am I able to tweak this code to receive 2 or more UDP messages? Appreciate any advice.
至少在概念上,您需要将 getUdp() 方法分成三个独立的部分:一个 Setup() 部分,您在程序启动时调用一次,一个 Receive() 部分(仅包含recv() 调用),你可以调用任意多次,以接收下一个数据包,最后是一个 Cleanup() 部分,它关闭套接字并关闭 TCP 堆栈(只有当你的程序即将退出)。这样 UDP 套接字在您的程序 运行 的整个过程中保持有效并绑定到端口,因此 OS 将可靠地缓冲传入的 UDP 数据包以通过 recv() 提供给您的程序。