【问题标题】:recvfrom only receive few packets after that it goes in waiting staterecvfrom 只接收几个数据包,之后它进入等待状态
【发布时间】:2018-12-04 07:49:13
【问题描述】:

您好,我是 Socket 编程的新手,我尝试创建一个客户端服务器应用程序,其中我的服务器是相机,而我的 C++ 应用程序中的客户端。 当我看到计算机和相机之间的数据包传输时,它显示相机正在发送超过 150000 个数据包,然后它就停止了。但是当我收到我能够收到400 - 450 packets 之后,recvfrom 函数进入等待状态。如果我再次运行该 exe 文件而不停止前一个文件,它会再次收到 400-450 packets

接收数据包的代码

SOCKET out1 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
    if (out1 == INVALID_SOCKET)
    {
        cout << out1 << endl;
    }
    server.sin_family = AF_INET;
    server.sin_port = htons(3956);
    inet_pton(AF_INET, "192.168.1.140", &server.sin_addr);
    int serverLength = sizeof(server);

    connect(out1, (sockaddr*)&server, serverLength);
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        int bytesIn = recvfrom(out1, buf, 1444, 0, (sockaddr*)&server, &serverLength);
        if (bytesIn > 0)
        {
            cout << "Image Received :" << bytesIn <<packet_counter << endl;
            packet_counter++;
        }
        else
        {
            cout << "Not Received : " << endl;
        }
    }

我正在以管理员权限运行 .exe。

那么谁能告诉我为什么recvfrom函数进入等待状态。

提前致谢。

编辑:-

抱歉,我提供了整个代码。

  #include <stdio.h>
#include <Windows.h>
#include <thread>
#include <WinSock2.h>

// Library
#pragma comment(lib, "ws2_32.lib")

using namespace std;

//***** Function Decleration *****//
void _packetConfig(SOCKET);
void _sendPacket(SOCKET, const char*, int, int);

// Global Variable
sockaddr_in server;

//***** Main Function *****//
void main(char argc, char* argv[])
{
    WSADATA data;
    WORD version = MAKEWORD(2, 2);
    if(WSAStartup(version, &data) == SOCKET_ERROR)
    {
        cout << "Can't Start Socket" << WSAGetLastError<<endl;
        return;
    }
    char buf[2000];

        SOCKET out1 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
        if (out1 == INVALID_SOCKET)
        {
            cout << out1 << endl;
        }
        server.sin_family = AF_INET;
        server.sin_port = htons(3956);
        inet_pton(AF_INET, "192.168.1.140", &server.sin_addr);
        int serverLength = sizeof(server);

        connect(out1, (sockaddr*)&server, serverLength);


        int packet_counter = 0;


        SOCKET out = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

        _packetConfig(out);

        cout << "Inside Main" << endl;
        while (1)
        {
            //connect(out1, (sockaddr*)&server, serverLength);
            memset(buf, 0, sizeof(buf));
            int bytesIn = recvfrom(out1, buf, 1444, 0, (sockaddr*)&server, &serverLength);
            if (bytesIn > 0)
            {
                cout << "Image Received :" << bytesIn <<packet_counter << endl;
                packet_counter++;
            }
            else
            {
                cout << "Not Received : " << endl;
            }
        }

        WSACleanup();
}

//***** Function to Send Bytes to the Camera *****//
void _sendPacket(SOCKET sock, const char* s, int len, int i)
{
    int sendOk = sendto(sock, (const char*)s, len, 0, (sockaddr*)&server, sizeof(server));

    if (sendOk == SOCKET_ERROR)
    {
        cout << "Didn't Work" << WSAGetLastError() << endl;
    }
    else
    {
        cout << "\nSend Succesfully" << " " << i << endl;
    }
    char buf[2000];
    int serverLength = sizeof(server);
    int bytesIn = recvfrom(sock, buf, 2000, 0, (sockaddr*)&server, &serverLength);
    if (bytesIn > 0)
    {
        cout << "Message Received :" << bytesIn << endl;
    }
}

//***** Function to call the _sendPacket function and send commands to the Camera *****//
void _packetConfig(SOCKET sock)
{
    // 59 Commands and every command call _snedPacket function to send commands to camera  it will working properly
}

在上面的代码中,我必须先发送这个59 commands写在_packetConfig函数然后只有相机会发送Image packets我收到所有命令的回复。

当我也使用该代码运行 wireshark 时,我可以看到在这 59 个命令之后 相机给出3580*51数据包。即51帧,每帧包含3580个数据包

【问题讨论】:

  • recvfrom 失败后,errno 中的内容是什么?另外,为什么要将套接字创建为SOCK_RAW?我想你想要SOCK_DGRAM
  • 我没有收到错误,或者 else 部分在收到 400-450 个数据包后打印卡在 recvfrom 函数中的代码
  • 不,如果我使用 SOCK_DGRAM 我无法获取数据包我不知道为什么正如我之前所说的,我对套接字不太了解。
  • 请显示发送代码(全部)。谢谢。
  • 我应该显示整个代码吗?

标签: c++ sockets camera udp packets


【解决方案1】:

感谢您发布代码。它实际上有一些问题,所以首先我将发布一些代码作为参考,然后提到我在你的代码中注意到的主要问题。

好的,下面是一些适合我的代码:

#include <WinSock2.h>                   // ** before** windows.h
#include <WS2tcpip.h>
#include <iostream>
#include <stdio.h>
#include <Windows.h>
#include <assert.h>

#pragma comment (lib, "ws2_32.lib")

const int port = 3956;

// main
int main (char argc, char* argv[])
{
    WSADATA wsadata;
    WORD version = MAKEWORD(2, 2);

    int err = WSAStartup (MAKEWORD (2, 2), &wsadata);
    if (err)
    {
        std::cout << "WSAStartup failed, error: " << err << std::endl;
        return 255;
    }

    char buf [1444];
    bool send = argc > 1 && _stricmp (argv [1], "send") == 0;

    if (send)
    {
        // Send
        SOCKET skt_out = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        assert (skt_out != INVALID_SOCKET);

        sockaddr_in destination_address = { };
        destination_address.sin_family = AF_INET;
        destination_address.sin_port = htons (port);
        inet_pton (AF_INET, "192.168.1.2", &destination_address.sin_addr);
        memset (buf, 'Q', sizeof (buf));
        printf ("Sending: ");

        for ( ; ; )
        {
            sendto (skt_out, buf, sizeof (buf), 0, (const sockaddr *) &destination_address, sizeof (destination_address));
            printf (".");
            Sleep (50);
        }

        closesocket (skt_out);
        WSACleanup ();
        return 0;
    }

    // Receive
    SOCKET skt_in = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    assert (skt_in != INVALID_SOCKET);

    int receive_buffer_size = 65536;
    if ((setsockopt (skt_in, SOL_SOCKET, SO_RCVBUF, (const char *) &receive_buffer_size, sizeof (int)) ) < 0)
        std::cout << "Could not set SO_RCVBUF, error: " << WSAGetLastError () << std::endl;

    sockaddr_in receive_address = { };
    receive_address.sin_family = AF_INET;
    receive_address.sin_port = htons (port);
    receive_address.sin_addr.s_addr = htonl (INADDR_ANY);

    if (bind (skt_in, (const sockaddr *) &receive_address, sizeof (receive_address)) == -1)
    {
        std::cout << "bind failed , error: " << WSAGetLastError () << std::endl;
        return 255;
    }

    int packetCounter = 0;
    printf ("Receiving: ");

    for ( ; ; )
    {
        int bytesIn = recvfrom (skt_in, buf, sizeof (buf), 0, NULL, 0);
        if (bytesIn > 0)
            std::cout << "Packet received:" << bytesIn << " bytes (" << ++packetCounter << ")" << std::endl;
        else
            std::cout << "Receive error: " << WSAGetLastError () << std::endl;
    }

    closesocket (skt_in);
    WSACleanup ();
    return 0;
}

要在“发送”模式下运行,请将 send 指定为命令行的第一个参数。否则,它充当接收者(又名服务器)。

那么您的代码有什么问题?好吧,没有特别的顺序:

  • 正如我们已经说过的,你不应该使用SOCK_RAW
  • 您需要在接收套接字上调用bind,以便它知道要侦听的端口。 recvfromsockaddr *from 参数并不代表您认为的意思(请查看 docs)。你会看到我将它作为 NULL 传递。
  • 您误解了WSAStartup 的返回值。再次,请查看文档。

但说了这么多,实际上你错过了对bind 的调用。我重写了代码,因为你的代码比较乱。

另外,重要的细节是,UDP 不保证传送 - 已发送的数据包没有被接收或什至可能被乱序接收的原因有很多(您的相机是否以某种方式对数据包进行排序?)
您需要在应用程序的逻辑中满足这一点(这是一个问题,最好使用 TCP,它确实可以保证数据包的传递和排序)。

【讨论】:

  • 谢谢先生,它正在使用 SOCK_DGRAM 并且系统正在捕获所有图像数据包,但是当我在 recvfrom 函数中打印任何内容时,我认为它错过了打印所有数据包接收的语句。
  • 是的,它可能会。如果发送方发送数据包的速度快于接收方读取数据包的速度,那么一些数据包将被悄悄丢弃因为 UDP 不保证传送。你应该很可能实际上在这里使用 TCP,除非有一个非常很好的理由不这样做。
  • 但是相机使用的是UDP协议。他们有什么办法可以让我全部收到吗?
  • @ChandrapalSinghJhala 使用setsockopt() 来增加套接字接收缓冲区的大小。并确保您不会在接收之间浪费时间处理数据包。尽可能快地读取,通常通过在一个线程中读取和排队数据包并在另一个线程中处理它们。
  • @Chandra 这听起来是个好主意。抱歉,我忘记你是从摄像机流式传输的。我已经添加了我的答案(并摆脱了errno - 改用WSAGetLastError())。
猜你喜欢
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
  • 2022-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 1970-01-01
相关资源
最近更新 更多