gpt4 book ai didi

c - 从不同的线程通过 UDP 进行多播

转载 作者:太空宇宙 更新时间:2023-11-03 22:16:02 26 4
gpt4 key购买 nike

我正在尝试创建一个应用程序,它允许我使用特定的多播地址通过 LAN 多播我的网络摄像头馈送,并使用 sendto() 来发送帧缓冲区。我正在尝试构建的应用程序与此站点上的应用程序几乎相同 http://nashruddin.com/Streaming_OpenCV_Videos_Over_the_Network并使用相同的架构。只是我使用 SOCK_DGRAM 而不是 TCP 套接字。问题是,当我从另一个线程使用 sendto() 函数时,它往往会失败,即它返回 -1 并且 errno 设置为 90 (EMSGSIZE),这基本上意味着形成的数据包太大而无法通过网络。但即使我尝试将一个简单的字符串(如“hello”)发送到同一个多播地址,也会发生这种情况。如果应用程序是单线程应用程序,这似乎工作正常。也就是说我只是捕获图像并在同一个线程中将其全部广播。这是代码:

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "cv.h"
#include "highgui.h"

#define PORT 12345
#define GROUP "225.0.0.37"
CvCapture* capture;
IplImage* img0;
IplImage* img1;
int is_data_ready = 0;
int serversock, clientsock;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* streamServer(void* arg);
void quit(char* msg, int retval);

int main(int argc, char** argv)
{
pthread_t thread_s;
int key;

if (argc == 2) {
capture = cvCaptureFromFile(argv[1]);
} else {
capture = cvCaptureFromCAM(0);
}

if (!capture) {
quit("cvCapture failed", 1);
}

img0 = cvQueryFrame(capture);
img1 = cvCreateImage(cvGetSize(img0), IPL_DEPTH_8U, 1);

cvZero(img1);
cvNamedWindow("stream_server", CV_WINDOW_AUTOSIZE);

/* print the width and height of the frame, needed by the client */
fprintf(stdout, "width: %d\nheight: %d\n\n", img0->width, img0->height);
fprintf(stdout, "Press 'q' to quit.\n\n");

/* run the streaming server as a separate thread */
if (pthread_create(&thread_s, NULL, streamServer, NULL)) {
quit("pthread_create failed.", 1);
}

while(key != 'q') {
/* get a frame from camera */
img0 = cvQueryFrame(capture);
if (!img0) break;

img0->origin = 0;
cvFlip(img0, img0, -1);

/**
* convert to grayscale
* note that the grayscaled image is the image to be sent to the client
* so we enclose it with pthread_mutex_lock to make it thread safe
*/
pthread_mutex_lock(&mutex);
cvCvtColor(img0, img1, CV_BGR2GRAY);
is_data_ready = 1;
pthread_mutex_unlock(&mutex);

/* also display the video here on server */
cvShowImage("stream_server", img0);
key = cvWaitKey(30);
}

/* user has pressed 'q', terminate the streaming server */
if (pthread_cancel(thread_s)) {
quit("pthread_cancel failed.", 1);
}

/* free memory */
cvDestroyWindow("stream_server");
quit(NULL, 0);
}

/**
* This is the streaming server, run as a separate thread
* This function waits for a client to connect, and send the grayscaled images
*/
void* streamServer(void* arg)
{
struct sockaddr_in server;

/* make this thread cancellable using pthread_cancel() */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

/* open socket */
if ((serversock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
quit("socket() failed", 1);
}
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = inet_addr(GROUP);
int opt = 1;
//if(setsockopt(serversock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(int))==-1){
// quit("setsockopt failed",0);
//}
// /* setup server's IP and port */
// memset(&server, 0, sizeof(server));
// server.sin_family = AF_INET;
// server.sin_port = htons(PORT);
// server.sin_addr.s_addr = INADDR_ANY;
//
// /* bind the socket */
// if (bind(serversock, (const void*)&server, sizeof(server)) == -1) {
// quit("bind() failed", 1);
// }
//
// /* wait for connection */
// if (listen(serversock, 10) == -1) {
// quit("listen() failed.", 1);
// }
//
// /* accept a client */
// if ((clientsock = accept(serversock, NULL, NULL)) == -1) {
// quit("accept() failed", 1);
// }

/* the size of the data to be sent */
int imgsize = img1->imageSize;
int bytes=0, i;

/* start sending images */
while(1)
{
/* send the grayscaled frame, thread safe */
pthread_mutex_lock(&mutex);
if (is_data_ready) {
// bytes = send(clientsock, img1->imageData, imgsize, 0);
is_data_ready = 0;
if((bytes = sendto(serversock,img1->imageData,imgsize,0,(struct sockaddr*)&server,sizeof(server)))==-1){
quit("sendto FAILED",1);
}
}
pthread_mutex_unlock(&mutex);

// /* if something went wrong, restart the connection */
// if (bytes != imgsize) {
// fprintf(stderr, "Connection closed.\n");
// close(clientsock);
//
// if ((clientsock = accept(serversock, NULL, NULL)) == -1) {
// quit("accept() failed", 1);
// }
// }

/* have we terminated yet? */
pthread_testcancel();

/* no, take a rest for a while */
usleep(1000);
}
}

/**
* this function provides a way to exit nicely from the system
*/
void quit(char* msg, int retval)
{
if (retval == 0) {
fprintf(stdout, (msg == NULL ? "" : msg));
fprintf(stdout, "\n");
} else {
fprintf(stderr, (msg == NULL ? "" : msg));
fprintf(stderr, "\n");
}

if (clientsock) close(clientsock);
if (serversock) close(serversock);
if (capture) cvReleaseCapture(&capture);
if (img1) cvReleaseImage(&img1);

pthread_mutex_destroy(&mutex);

exit(retval);
}

最佳答案

sendto() 调用中,您引用了初始化为 img1->imageSizeimgsize。但我看不到 img1->imageSize 的设置位置,并且 imgsize 似乎从未更新过。

因此首先检查传递给sendto()imgsize 值是否正确。然后检查它是否太大:

UDP/IP 数据报的硬负载限制为 65,507 字节。但是,不需要 IPv4 网络支持超过 548 字节的有效负载。 (576 是最小 IPv4 MTU 大小,减去 28 字节的 UDP/IP 开销)。大多数网络的 MTU 为 1500,标称负载为 1472 字节。

大多数网络允许您通过将数据报分成 IP 片段来超过 MTU,接收操作系统必须重新组装这些片段。这对您的应用程序是不可见的:recvfrom() 要么获取整个重新组装的数据包,要么一无所获。但是什么也得不到的几率会随着分段而增加,因为任何分段的丢失都会导致整个数据包丢失。此外,某些路由器和操作系统具有模糊的安全规则,这些规则会阻止某些 UDP 模式或特定大小的片段。

最后,任何给定的网络都可能强制执行最大数据报大小,即使有碎片,这通常远小于 65507 字节。

由于您正在处理一个特定的网络,您将需要进行试验以了解您可以可靠地发展到多大。

UDP/IP at Wikipedia

IPv4 at Wikipedia

关于c - 从不同的线程通过 UDP 进行多播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8804006/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com