我无法在网上找到我做错的事。
我的问题是,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()
。
答案 0 :(得分:2)
将MSG_PEEK与recvfrom一起使用不会从传入数据队列中删除数据,下次调用recvfrom时它仍然存在。