从Java客户端发送帧到C++服务器通过UDP

发布于 2025-02-12 10:48:48 字数 2343 浏览 0 评论 0原文

我正在尝试使用C ++实现UDP服务器,以从客户端接收帧。我正在使用此问题作为参考。唯一的区别是,我有一个Java客户端,该客户端通过UDP:

Java客户端发送帧,该客户端通过UDP:

byte[] buffer = GetImageByte(FrameData,384,288,false); //GetImageByte is a function that returns a raw frame
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("127.0.0.1");
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, IPAddress, 9999);
clientSocket.send(packet); 

C ++服务器发送图像,它接收UDP映像:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[1024];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    int height = 384;
    int width= 288;


    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(9999);


    Mat img = Mat::zeros( height,width, CV_8UC3);
    int imgSize = img.total()*img.elemSize();
    uchar sockData[imgSize];
    int bytes = 0; 
    for (int i = 0; i < imgSize; i += bytes) {
        if ((bytes = recv(sockfd, sockData +i, imgSize  - i, 0)) == -1)  {
            break;
        }
        
    }
    int ptr=0;
    for (int i = 0;  i < img.rows; i++) {
        for (int j = 0; j < img.cols; j++) {                                     
            img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+ 0],sockData[ptr+1],sockData[ptr+2]);
            ptr=ptr+3;
    }
}


    Mat image(384,288,CV_8UC3,*buffer);
    close(newsockfd);
    close(sockfd);
    
    
    imshow( "Server", image);  
    waitKey(0);
    return 0; 
}

我想做的就是简单地接收帧并使用OpenCV显示。问题在于代码成功编译,但没有错误或任何有用的消息在控制台中显示。我测试了将图像发送到Python中的UDP服务器的工作。我想知道如何使用C ++通过UDP接收帧并使用OpenCV在屏幕上显示它?

I am trying to implement a UDP server with C++ to receive frames from the client. I am using this question as reference. Only difference is that I have a Java Client that sends the frames via udp:

Java client that sends image via UDP:

byte[] buffer = GetImageByte(FrameData,384,288,false); //GetImageByte is a function that returns a raw frame
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("127.0.0.1");
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, IPAddress, 9999);
clientSocket.send(packet); 

C++ server that receives udp image:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[1024];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    int height = 384;
    int width= 288;


    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(9999);


    Mat img = Mat::zeros( height,width, CV_8UC3);
    int imgSize = img.total()*img.elemSize();
    uchar sockData[imgSize];
    int bytes = 0; 
    for (int i = 0; i < imgSize; i += bytes) {
        if ((bytes = recv(sockfd, sockData +i, imgSize  - i, 0)) == -1)  {
            break;
        }
        
    }
    int ptr=0;
    for (int i = 0;  i < img.rows; i++) {
        for (int j = 0; j < img.cols; j++) {                                     
            img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+ 0],sockData[ptr+1],sockData[ptr+2]);
            ptr=ptr+3;
    }
}


    Mat image(384,288,CV_8UC3,*buffer);
    close(newsockfd);
    close(sockfd);
    
    
    imshow( "Server", image);  
    waitKey(0);
    return 0; 
}

What I am trying to do is simply receive a frame and show it using OpenCV. The problem is that the code compiles successfully but no errors or any helpful message is shown in the console whatsoever. I tested sending the image to a UDP server in Python it works. I'd like to know how can I receive a frame via UDP using C++ and show it on screen using OpenCv?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡看悲欢离合 2025-02-19 10:48:48

在与OPENCV参考的简短咨询之后,上面似乎正在使用384x288三个通道图像,该图像总计高达324KB的数据。

Java客户端似乎正在尝试构建此大小的单个数据报数据,然后一次发送。

能够在任何地方发送单个UDP 324KB数据包的机会很小。单个UDP插座的最大大小未指定,取决于基础网络套接字; 508字节是具有现代网络协议的普遍最大尺寸。

这是您的C ++代码暗示的,该代码使用循环尝试读取整个帧(由于不久的是提到的原因,这也有些天真,但现在就将其搁置一旁)。您将需要在发送代码中添加适当的逻辑才能将其分解。

这样做后,您将遇到下一个问题:UDP绝对不能保证您发送的任何UDP数据包将被收到。从定义上讲,UDP缺乏任何类型的重传逻辑,也不是保证的运输层。这在每个侧重于网络编程的教科书中都对此进行了解释。

通过复杂的速率限制,检测和适应可用的带宽,以及使用复杂的逻辑来处理偶尔掉落的数据包,常见的媒体流媒体平台通过复杂的速率限制,检测和适应可靠的速率来实现或多或少可靠的流媒体流。最大程度地减少了一定程度的冗余的掉落数据包的影响(YouTube流中的单个掉落框架几乎不会注意到,并且在音频流中有轻微的,暂时的,暂时的退化)。当Java发件人只是尽快将它们爆炸出来时,成功接收加起来324KB图像的每个数据包的机会并不是很有希望。

因此,在这里,您可以为您提供大量的工作,以发明和实施所有这些基础算法的版本,以在UDP之上实施某种节流的流媒体机制。坦率地说,切换到TCP,使其与TCP一起使用,然后尝试在事实之后在UDP之上实现所有这些。

最终注意:

    uchar sockData[imgSize];

这也不有效C ++。可变长度阵列是非标准的C ++,只是编译器支持的非标准C ++扩展。此外,这将使您的堆栈中的上述324KB吞噬一口气。

尽管现代的C ++实现通常会有很多可用的堆栈空间:养成这样做的习惯最终会导致眼泪。不要这样做,请使用std :: vector

After a brief consultation with OpenCV reference, the above appears to be working with 384x288 three channel image, which adds up to 324kb worth of data.

The Java client appears to be attempting to construct a single datagram packet, of this size, then send it all at once.

The chances of being able to send a single UDP 324kb packet, anywhere, are slim to none. The maximum size of a single UDP socket is unspecified and depends on the underlying network socket; 508 bytes is the generally accepted maximum size, with modern network protocols.

This is implied by your C++ code, which uses a loop to attempt to read the entire frame (which is also somewhat naive, for the reasons mentioned shortly, but let's set this aside for now). You will need to add appropriate logic to the sending code to break it up.

Once you do this you will run into the next problem: UDP gives you absolutely no guarantees, whatsoever, that any UDP packet you send will be received. UDP, by definition, lacks any kind of retransmission logic, and is not a guaranteed delivery transport layer. This is explained in every textbook that focuses on network programming.

Common media streaming platforms achieve more or less reliable streaming over UDP through a combination of sophisticated rate limiting, detecting and adapting to the available bandwidth, and using complicated logic that deals with occasional dropped packets; minimizing the impact of dropped packets with some level of redundancy (a single dropped frame in a Youtube stream will be hardly noticed, as well as a slight, temporary, degradation in the audio stream). The chances of successfully receiving every one of the packets that adds up to the 324kb image, when the Java sender simply blasts them out, as fast as it can, are not very promising.

So, you have lot of work cut out for you, here, inventing and implementing your own versions of all of these underlying algorithms, for implementing some kind of a throttled streaming mechanism on top of UDP. It will be frankly easier to switch to TCP, get it working with TCP, then attempt to implement all of this on top of UDP after the fact.

One final note:

    uchar sockData[imgSize];

This is not valid C++ either. Variable length arrays are non-standard C++, and are only a non-standard C++ extension that your compiler supports. Additionally, this will eat the aforementioned 324kb out of your stack, all in one gulp.

Although modern C++ implementations will typically have so much stack space available: getting into a habit of doing this will eventually lead to tears. Don't do this, use std::vector.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文