UDP套接字编程c ++ Recvfrom()函数错误

时间:2018-01-05 19:12:25

标签: c++ sockets udp

我无法在网上找到我做错的事。

我的问题是,recvfrom()函数似乎记住了最后一个值,而不是进行新的调用并更新缓冲区。

我已经使用Python创建了相同的代码逻辑,它可以找到但我无法找到在C ++中执行相同操作的方法。

这就是我的代码:

#define _WINSOCKAPI_
#include <windows.h>
#include <winsock2.h>
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <time.h>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;

int main()
{
    cout << "\t\t--------------UDP Server ---------------" << endl;
    cout << endl;

    WSADATA WinSockData;
    int iWsaStartup, iWsaCleanup;

    SOCKET UDPSocketServer;
    struct sockaddr_in UDPClient;

    char Buffer[200];

    int iBind, iReceiveFrom;

    int iUDPClientLen = sizeof(UDPClient);
    int iCloseSocket;

    int response, offset;
    ULONG cmd = 0;

    iWsaStartup = WSAStartup(MAKEWORD(2, 2), &WinSockData);

    if (iWsaStartup != 0) {
        cout << "WSAStartup Failed" << endl;
    }
    cout << "WSAStartup Success" << endl;

    //Setting Socket connexion information
    UDPClient.sin_family = AF_INET;
    UDPClient.sin_addr.s_addr = htons(INADDR_ANY);
    UDPClient.sin_port = htons(40100);

    //Informations to send to this address
    const char* msg = "///";
    size_t msg_length = sizeof(msg) - 1;
    struct sockaddr_in myaddr;
    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_addr.s_addr = inet_addr("192.128.20.65");
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(40100);

    //Create Socket
    UDPSocketServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (UDPSocketServer == INVALID_SOCKET) {
        cout << "Socket creation failed with error : " << WSAGetLastError() << endl;
        WSACleanup();
        exit(0);
    }
    cout << "Socket creation success" << endl;

    //Binding Socket to INADDR_ANY 0.0.0.0:40100
    iBind = bind(UDPSocketServer, (SOCKADDR*)&UDPClient, sizeof(UDPClient));
    if (iBind == SOCKET_ERROR) {
        cout << "Binding failed with error : " << WSAGetLastError() << endl;
        closesocket(UDPSocketServer);
        WSACleanup();
        exit(0);
    }
    cout << "Binding success" << endl;

    //Make sure the socket is blocking
    if (ioctlsocket(UDPSocketServer, FIONBIO, &cmd) == SOCKET_ERROR) {
        cout << "ioctlsocket failed with error : " << WSAGetLastError() << endl;
    }
    else
        cout << "ioctlsocket success : " << cmd << endl; //Return 0 because it is set for Blocking

    //Send information to 192.128.20.65:40100
    response = sendto(UDPSocketServer, reinterpret_cast<const char*>(msg), msg_length, 0, (sockaddr*)&myaddr, sizeof(myaddr));
    if (response == SOCKET_ERROR) {
        cout << "Send failed with error : " << WSAGetLastError() << endl;
    }
    cout << "Send success : " << response << endl;

    //Wait 4 seconds
    Sleep(4000);

    //Send information to 192.128.20.65:40100
    response = sendto(UDPSocketServer, reinterpret_cast<const char*>(msg), msg_length, 0, (sockaddr*)&myaddr, sizeof(myaddr));
    if (response == SOCKET_ERROR) {
        cout << "Send failed with error : " << WSAGetLastError() << endl;
    }
    cout << "Send success : " << response << endl;

    while (1) {
        //Capture receive data from any address on port 40100
        //This is supose to be a blocking function but it never block after the first return call
        iReceiveFrom = recvfrom(UDPSocketServer, Buffer, sizeof(Buffer) + 1, MSG_PEEK, (SOCKADDR*)&UDPClient, &iUDPClientLen);
        if (iReceiveFrom == SOCKET_ERROR) {
            cout << "Receive failed with error : " << WSAGetLastError() << endl;
        }
        else if (iReceiveFrom != 0) {
            Buffer[iReceiveFrom] = '\0'; //Add end of line to Buffer
            //printf("%.*s\n", iReceiveFrom, Buffer);
            cout << "Receive success : " << Buffer << endl;
        }
    }
    iCloseSocket = closesocket(UDPSocketServer);

    iWsaCleanup = WSACleanup();
    if (iWsaCleanup == SOCKET_ERROR) {
        cout << "WSA Cleanup failed with error : " << WSAGetLastError() << endl;
    }
    cout << "WSA Cleanup success" << endl;

    system("PAUSE");
    return 0;
}

我创建了一个UDP C ++套接字,它将自身绑定到0.0.0.0:40100并使用函数recvfrom()侦听该端口。

问题是我的recvfrom()函数似乎永远不会更新或等待新数据。它只是发送相同的旧数据而无需等待。

我尝试添加一些会改变缓冲区所有值的代码,但是当调用recvfrom()时,收到的值与旧值相同。

根据我的阅读,recvfrom()函数应该是一个阻塞函数,但就我而言,它似乎不起作用。

通过查看ioctlsocket()功能响应,我确保该功能已被阻止;它被设置为0,所以它应该阻止。

我还试图为我的sendTo()函数创建一个新套接字,我得到了相同的结果。

最后,我还试图删除sendTo()函数,但是就像我在Python中的代码一样,如果我不在第一个字符串中发送字符串,那么似乎没有数据从套接字中恢复地点。 (Wireshark显示始终发送到此端口的数据。没有这个初始化,我无法在我的套接字上打印任何内容。)

我觉得奇怪的是,我的计算机上的某个端口收到了数据,但是当绑定到该端口时,我无法在将数据发送到首先发送它的地址之前看到这些数据。所以我认为问题可能发生在sendTo()电话和recvfrom()

之间

1 个答案:

答案 0 :(得分:2)

将MSG_PEEK与recvfrom一起使用不会从传入数据队列中删除数据,下次调用recvfrom时它仍然存在。