UDP客户端(接收方)不应该接收数据报

时间:2017-07-15 16:58:42

标签: c++ udp

我正在尝试从一个程序接收数据(X-Plane 10是特定的)。它应该由UDP连接完成。 XPlane发送的数据格式为(4 + n * 32)字节包(n-取决于Xplane内的设置)。 我试图通过以下代码接收它:

const int LEN = 256;
int server_length;
int port = 49010;

char* package = new char[LEN];

WSADATA wsaData;
SOCKET mySocket;
SOCKET myBackup;
SOCKET acceptSocket;
sockaddr_in myAddress;

int _tmain(int argc, _TCHAR* argv[])
{

//socket
if( WSAStartup( MAKEWORD(2, 2), &wsaData ) != NO_ERROR )
{
    cerr<<"Socket Initialization: Error with WSAStartup\n";
    system("pause");
    WSACleanup();
    exit(10);
}

mySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if (mySocket == INVALID_SOCKET)
{
    cerr<<"Error creating socket"<<endl;
    system("pause");
    WSACleanup();
    exit(11);
}


//binding
myAddress.sin_family = AF_INET;
myAddress.sin_addr.s_addr = inet_addr( "127.0.0.1" );
myAddress.sin_port = htons(port);

if(bind(mySocket, (SOCKADDR*) &myAddress, sizeof(myAddress)) == SOCKET_ERROR)
{
    cerr<<"Failed to connect\n";
    system("pause");
    WSACleanup();
    exit(14);
}

//receiving
while (true) 
{
    cout.flush();
    server_length = sizeof(struct sockaddr_in);
    myAddress.sin_port = htons(port);
    recvfrom(mySocket, package, LEN, 0, (SOCKADDR*) &myAddress, &server_length);
    printf( "%s\n", package );
}
    return 0;
}

我收到的只是DATA @ +,有时是一个随机符号。

我知道数据报的前5个字节应该是&#34; DATA @&#34;,所以我知道它的连接和或多或少的工作,但我不明白为什么它没有读取Xplane发送的其余数据。

编辑: 我在网上找到了一个代码,我在我的程序中使用了它。同样的结果:DATA @ ...

它也不会在文件中显示任何其他内容。

#define DEFAULT_PORT            49010
#define DEFAULT_COUNT           100
#define DEFAULT_BUFFER_LENGTH   41

int   iPort    = DEFAULT_PORT;          // Port to receive on
DWORD dwCount  = DEFAULT_COUNT,         // Number of messages to read
 dwLength = DEFAULT_BUFFER_LENGTH; // Length of receiving buffer
BOOL  bInterface = FALSE;               // Use an interface other than
                                // default
char  szInterface[32];            // Interface to read datagrams from

//
// Function: usage:
//
// Description:
//    Print usage information and exit
//
void usage()
{
printf("usage: sender [-p:int] [-i:IP][-n:x] [-b:x]\n\n");
printf("       -p:int   Local port\n");
printf("       -i:IP    Local IP address to listen on\n");
printf("       -n:x     Number of times to send message\n");
printf("       -b:x     Size of buffer to send\n\n");
ExitProcess(1);
}

//
// Function: ValidateArgs
//
// Description:
//    Parse the command line arguments, and set some global flags to
//    indicate what actions to perform
//
void ValidateArgs(int argc, char **argv) 
{
int                i;

for(i = 1; i < argc; i++)
{
    if ((argv[i][0] == '-') || (argv[i][0] == '/'))
    {
        switch (tolower(argv[i][1]))
        {
            case 'p':   // Local port
                if (strlen(argv[i]) > 3)
                    iPort = atoi(&argv[i][3]);
                break;
            case 'n':   // Number of times to receive message
                if (strlen(argv[i]) > 3)
                    dwCount = atol(&argv[i][3]);
                break;
            case 'b':   // Buffer size
                if (strlen(argv[i]) > 3)
                    dwLength = atol(&argv[i][3]);
                break;
            case 'i':   // Interface to receive datagrams on
                if (strlen(argv[i]) > 3)
                {
                    bInterface = TRUE;
                strcpy(szInterface, &argv[i][3]);
                }
                break;
            default:
                usage();
                break;
        }
    }
}
}

//
// Function: main
//
// Description:
//    Main thread of execution. Initialize Winsock, parse the command
//    line arguments, create a socket, bind it to a local interface
//    and port, and then read datagrams.
//
int main(int argc, char **argv)
{
WSADATA        wsd;
SOCKET         s;
char          *recvbuf = NULL;
int            ret,
               i;
int          dwSenderSize;
SOCKADDR_IN    sender,
               local;

// Parse arguments and load Winsock
//
ValidateArgs(argc, argv);

if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
    printf("WSAStartup failed!\n");
    return 1;
}
// Create the socket and bind it to a local interface and port
//
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == INVALID_SOCKET)
{
    printf("socket() failed; %d\n", WSAGetLastError());
    return 1;
}
local.sin_family = AF_INET;
local.sin_port = htons((short)iPort);
if (bInterface)
    local.sin_addr.s_addr = inet_addr(szInterface);
else
    local.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)
{
    printf("bind() failed: %d\n", WSAGetLastError());
    return 1;
}
// Allocate the receive buffer
//
recvbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength);
if (!recvbuf)
{
    printf("GlobalAlloc() failed: %d\n", GetLastError());
    return 1;
}
// Read the datagrams
//

std::ofstream myfile;
myfile.open ("file.txt");


for(i = 0; i < dwCount; i++)
{
    dwSenderSize = sizeof(sender);
    ret = recvfrom(s, recvbuf, dwLength, 0,
        (SOCKADDR *)&sender, &dwSenderSize);
    if (ret == SOCKET_ERROR)
    {
        printf("recvfrom() failed; %d\n", WSAGetLastError());
        break;
    }
    else if (ret == 0)
        break;
    else
    {
        recvbuf[ret] = '\0';
        printf("[%s] sent me: '%s'\n",
            inet_ntoa(sender.sin_addr), recvbuf);
        myfile << recvbuf<<endl;
    }
}
closesocket(s);

GlobalFree(recvbuf);
WSACleanup();
myfile.close();
return 0;
}

1 个答案:

答案 0 :(得分:0)

printf( "%s\n", package );

这是一个C风格的函数,期望得到一个C风格的字符串,以\0字节结束。

显示的代码使用package分配此new缓冲区,但无法清除或初始化此缓冲区。因此,package的初始内容是随机垃圾。然后显示的代码在缓冲区中接收一些数据:

recvfrom(mySocket, package, LEN, 0, (SOCKADDR*) &myAddress, &server_length);

recvfrom()返回实际收到的字节数,但显示的代码完全忽略了这一点。因此,无论实际收到什么,都会被放入packagepackage缓冲区的其余部分仍包含上述随机垃圾,它最初包含在内。

所显示的代码中没有任何内容在接收到的数据包的最后一个字节之后正确附加\0。因此,当显示的代码尝试printf package指针时,recvfrom()的实际内容将跟随缓冲区中的任何随机垃圾,直到printf找到,通过平局的运气,一些\0,在那里的某个地方。