UDP 通信不工作。使用 WinSock2 库
UDP communication is not working. Using the WinSock2 library
我写了两个简单的程序,都使用UDP。其中一个发送数据包,另一个接收数据包。
我运行这两个程序都在以下情况下:
- 防火墙已关闭。
- 我转发了相应的端口,即使我在我的局域网上测试了它。
我在使用本地主机时对其进行了测试,运行 这两个程序在同一台计算机上。但是没用。
发送程序:
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"
#define CYCLECOUNT 100
#define MESS "Hello world!"
int main()
{
/// True if the socket is initialized.
bool bSockInit = false;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cout << "Failed the startup with error: " << err << '\n';
goto END;
}
/// Creating the socket.
SOCKET sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto END;
}
bSockInit = true;
/// Creating the address, to which data is sent.
sockaddr_in remoteAddr;
ZeroMemory((PVOID) &remoteAddr, sizeof(remoteAddr));
// Setting the address familiy to ipv4.
remoteAddr.sin_family = AF_INET;
// Setting the port in network byte order.
remoteAddr.sin_port = htons(PORT);
// Setting the address from a c-style string.
InetPton(AF_INET, TEXT(IPSTR), (PVOID) &remoteAddr.sin_addr);
/// Sending the messages.
while (std::cin.get() == '\n')
{
int byteCount = 0;
for (int i = 0; i < CYCLECOUNT; ++i)
{
byteCount += sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
}
/// Print the number of bytes sent.
std::cout << "Sent " << byteCount << " bytes times to " IPSTR ":" PORTSTR << ".";
}
END:
// If the socket was initialized successfully then dispose of it.
if (bSockInit)
{
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
}
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
std::cin.get();
return 0;
}
接收程序:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
// The port where data is to be received.
#define PORT 1243
int main(int argc, char** argv)
{
/// True if the socket is initialized.
bool bSockInit = false;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cout << "Failed the startup with error: " << err << '\n';
goto END;
}
/// Creating the socket.
SOCKET sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto END;
}
bSockInit = true;
/// Creating the address.
sockaddr_in thisAddr;
ZeroMemory((PVOID) &thisAddr, sizeof(thisAddr));
// Setting the address familiy to ipv4.
thisAddr.sin_family = AF_INET;
// Setting the port in network byte order.
thisAddr.sin_port = htons(PORT);
// Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
thisAddr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
{
std::cout << "Failed the bind with error: " << WSAGetLastError() << '\n';
goto END;
}
// Buffer to store incoming bytes.
char buf[1024];
// The number of bytes that were received.
int len;
// Data about the sender.
sockaddr from;
int fromlen;
fromlen = 0;
// ~Data about the sender.
// Waiting for a message, containing at least one byte to arrive.
while ((len = recvfrom(sock, buf, sizeof(buf), NULL, &from, &fromlen)) <= 0);
// Printing the message that was just received and placed into the buffer.
for (int i = 0; i < len; ++i)
{
std::cout << buf[i];
}
END:
// If the socket was initialized successfully then dispose of it.
if (bSockInit)
{
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
}
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
std::cin.get();
return 0;
}
如果您有空闲时间,运行 两个程序,看看会发生什么。
要使用发送程序发送数据,您需要按 ENTER/RETURN 键。
我也很欣赏此类程序的示例。
在发件人上,您根本没有对 sendto()
进行任何错误处理。
在接收器上,您的读取循环在每次调用 recvfrom()
时都没有正确设置 fromlen
,这可能会使 recvfrom()
失败并出现 WSAEFAULT
错误,您没有处理或报告。如果 recvfrom()
失败,您将陷入无限循环。此外,您的 std::cout
输出应该在读取循环内,仅当 recvfrom()
成功时才将数据写入控制台。此外,recvfrom()
返回 0 不是错误条件,因为与 TCP 不同,UDP 允许 0 字节消息。
试试这个:
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"
#define CYCLECOUNT 100
#define MESS "Hello world!"
int main()
{
SOCKET sock = INVALID_SOCKET;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cerr << "Failed the startup with error: " << err << '\n';
goto FINISHED;
}
/// Creating the socket.
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto CLEANUPWSA;
}
/// Creating the address, to which data is sent.
sockaddr_in remoteAddr;
ZeroMemory(&remoteAddr, sizeof(remoteAddr));
// Setting the address familiy to ipv4.
remoteAddr.sin_family = AF_INET;
// Setting the port in network byte order.
remoteAddr.sin_port = htons(PORT);
// Setting the address from a c-style string.
inet_pton(AF_INET, IPSTR, &remoteAddr.sin_addr);
/// Sending the messages.
while (std::cin.get() == '\n')
{
int byteCount = 0;
for (int i = 0; i < CYCLECOUNT; ++i)
{
int sent = sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
if (sent == SOCKET_ERROR)
{
std::cerr << "Failed the send with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
byteCount += sent;
}
/// Print the number of bytes sent.
std::cout << "Sent " << byteCount << " bytes to " << IPSTR << ":" << PORTSTR << ".";
}
CLEANUPSCKT:
// If the socket was initialized successfully then dispose of it.
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
CLEANUPWSA:
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
FINISHED:
std::cin.get();
return 0;
}
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
// The port where data is to be received.
#define PORT 1243
int main(int argc, char** argv)
{
SOCKET sock = INVALID_SOCKET;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cerr << "Failed the startup with error: " << err << '\n';
goto FINISHED;
}
/// Creating the socket.
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto CLEANUPWSA;
}
/// Creating the address.
sockaddr_in thisAddr;
ZeroMemory(&thisAddr, sizeof(thisAddr));
// Setting the address familiy to ipv4.
thisAddr.sin_family = AF_INET;
// Setting the port in network byte order.
thisAddr.sin_port = htons(PORT);
// Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
thisAddr.sin_addr.s_addr = htonl(ADDR_ANY);
if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
{
std::cerr << "Failed the bind with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
// Buffer to store incoming bytes.
char buf[1024];
// The number of bytes that were received.
int len;
// Data about the sender.
sockaddr_in from;
int fromlen;
// Waiting for a message, containing at least one byte to arrive.
do
{
fromlen = sizeof(from);
len = recvfrom(sock, buf, sizeof(buf), NULL, (sockaddr*)&from, &fromlen);
if (len == SOCKET_ERROR)
{
std::cerr << "Failed the recv with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
std::cout << "Received " << len << " byte(s) from " << inet_ntoa(from.sin_addr.s_addr) << ":" << ntohs(from.sin_port);
if (len > 0)
{
// Printing the message that was just received and placed into the buffer.
std::cout << ": ";
std::cout.write(buf, len);
std::cout << '\n';
break;
}
std::cout << ", still waiting" << '\n';
}
while (true);
CLEANUPSCKT:
// If the socket was initialized successfully then dispose of it.
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
CLEANUPWSA:
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
FINISHED:
std::cin.get();
return 0;
}
我写了两个简单的程序,都使用UDP。其中一个发送数据包,另一个接收数据包。
我运行这两个程序都在以下情况下:
- 防火墙已关闭。
- 我转发了相应的端口,即使我在我的局域网上测试了它。
我在使用本地主机时对其进行了测试,运行 这两个程序在同一台计算机上。但是没用。
发送程序:
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"
#define CYCLECOUNT 100
#define MESS "Hello world!"
int main()
{
/// True if the socket is initialized.
bool bSockInit = false;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cout << "Failed the startup with error: " << err << '\n';
goto END;
}
/// Creating the socket.
SOCKET sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto END;
}
bSockInit = true;
/// Creating the address, to which data is sent.
sockaddr_in remoteAddr;
ZeroMemory((PVOID) &remoteAddr, sizeof(remoteAddr));
// Setting the address familiy to ipv4.
remoteAddr.sin_family = AF_INET;
// Setting the port in network byte order.
remoteAddr.sin_port = htons(PORT);
// Setting the address from a c-style string.
InetPton(AF_INET, TEXT(IPSTR), (PVOID) &remoteAddr.sin_addr);
/// Sending the messages.
while (std::cin.get() == '\n')
{
int byteCount = 0;
for (int i = 0; i < CYCLECOUNT; ++i)
{
byteCount += sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
}
/// Print the number of bytes sent.
std::cout << "Sent " << byteCount << " bytes times to " IPSTR ":" PORTSTR << ".";
}
END:
// If the socket was initialized successfully then dispose of it.
if (bSockInit)
{
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
}
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
std::cin.get();
return 0;
}
接收程序:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
// The port where data is to be received.
#define PORT 1243
int main(int argc, char** argv)
{
/// True if the socket is initialized.
bool bSockInit = false;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cout << "Failed the startup with error: " << err << '\n';
goto END;
}
/// Creating the socket.
SOCKET sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto END;
}
bSockInit = true;
/// Creating the address.
sockaddr_in thisAddr;
ZeroMemory((PVOID) &thisAddr, sizeof(thisAddr));
// Setting the address familiy to ipv4.
thisAddr.sin_family = AF_INET;
// Setting the port in network byte order.
thisAddr.sin_port = htons(PORT);
// Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
thisAddr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
{
std::cout << "Failed the bind with error: " << WSAGetLastError() << '\n';
goto END;
}
// Buffer to store incoming bytes.
char buf[1024];
// The number of bytes that were received.
int len;
// Data about the sender.
sockaddr from;
int fromlen;
fromlen = 0;
// ~Data about the sender.
// Waiting for a message, containing at least one byte to arrive.
while ((len = recvfrom(sock, buf, sizeof(buf), NULL, &from, &fromlen)) <= 0);
// Printing the message that was just received and placed into the buffer.
for (int i = 0; i < len; ++i)
{
std::cout << buf[i];
}
END:
// If the socket was initialized successfully then dispose of it.
if (bSockInit)
{
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
}
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
std::cin.get();
return 0;
}
如果您有空闲时间,运行 两个程序,看看会发生什么。
要使用发送程序发送数据,您需要按 ENTER/RETURN 键。
我也很欣赏此类程序的示例。
在发件人上,您根本没有对 sendto()
进行任何错误处理。
在接收器上,您的读取循环在每次调用 recvfrom()
时都没有正确设置 fromlen
,这可能会使 recvfrom()
失败并出现 WSAEFAULT
错误,您没有处理或报告。如果 recvfrom()
失败,您将陷入无限循环。此外,您的 std::cout
输出应该在读取循环内,仅当 recvfrom()
成功时才将数据写入控制台。此外,recvfrom()
返回 0 不是错误条件,因为与 TCP 不同,UDP 允许 0 字节消息。
试试这个:
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"
#define CYCLECOUNT 100
#define MESS "Hello world!"
int main()
{
SOCKET sock = INVALID_SOCKET;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cerr << "Failed the startup with error: " << err << '\n';
goto FINISHED;
}
/// Creating the socket.
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto CLEANUPWSA;
}
/// Creating the address, to which data is sent.
sockaddr_in remoteAddr;
ZeroMemory(&remoteAddr, sizeof(remoteAddr));
// Setting the address familiy to ipv4.
remoteAddr.sin_family = AF_INET;
// Setting the port in network byte order.
remoteAddr.sin_port = htons(PORT);
// Setting the address from a c-style string.
inet_pton(AF_INET, IPSTR, &remoteAddr.sin_addr);
/// Sending the messages.
while (std::cin.get() == '\n')
{
int byteCount = 0;
for (int i = 0; i < CYCLECOUNT; ++i)
{
int sent = sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
if (sent == SOCKET_ERROR)
{
std::cerr << "Failed the send with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
byteCount += sent;
}
/// Print the number of bytes sent.
std::cout << "Sent " << byteCount << " bytes to " << IPSTR << ":" << PORTSTR << ".";
}
CLEANUPSCKT:
// If the socket was initialized successfully then dispose of it.
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
CLEANUPWSA:
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
FINISHED:
std::cin.get();
return 0;
}
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
// The port where data is to be received.
#define PORT 1243
int main(int argc, char** argv)
{
SOCKET sock = INVALID_SOCKET;
/// Initialization.
WSADATA wsaData;
if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
std::cerr << "Failed the startup with error: " << err << '\n';
goto FINISHED;
}
/// Creating the socket.
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
goto CLEANUPWSA;
}
/// Creating the address.
sockaddr_in thisAddr;
ZeroMemory(&thisAddr, sizeof(thisAddr));
// Setting the address familiy to ipv4.
thisAddr.sin_family = AF_INET;
// Setting the port in network byte order.
thisAddr.sin_port = htons(PORT);
// Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
thisAddr.sin_addr.s_addr = htonl(ADDR_ANY);
if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
{
std::cerr << "Failed the bind with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
// Buffer to store incoming bytes.
char buf[1024];
// The number of bytes that were received.
int len;
// Data about the sender.
sockaddr_in from;
int fromlen;
// Waiting for a message, containing at least one byte to arrive.
do
{
fromlen = sizeof(from);
len = recvfrom(sock, buf, sizeof(buf), NULL, (sockaddr*)&from, &fromlen);
if (len == SOCKET_ERROR)
{
std::cerr << "Failed the recv with error: " << WSAGetLastError() << '\n';
goto CLEANUPSCKT;
}
std::cout << "Received " << len << " byte(s) from " << inet_ntoa(from.sin_addr.s_addr) << ":" << ntohs(from.sin_port);
if (len > 0)
{
// Printing the message that was just received and placed into the buffer.
std::cout << ": ";
std::cout.write(buf, len);
std::cout << '\n';
break;
}
std::cout << ", still waiting" << '\n';
}
while (true);
CLEANUPSCKT:
// If the socket was initialized successfully then dispose of it.
std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
CLEANUPWSA:
std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';
FINISHED:
std::cin.get();
return 0;
}