UDP 客户端未收到 UDP 服务器消息

UDP client not receiving UDP server message

海友我是一个学习winsock2的新手。以下是我的udp服务器和客户端程序。

我这个程序客户端不知道服务器的IP地址,只知道端口。但是服务器在全网广播一条消息。

当客户端收到消息时,它会回溯服务器的 ip 并连接到它。

我的服务器和客户端在编译时都没有显示错误。

但是在执行客户端的 recvfrom() 语句时显示错误 以下是我的部分代码。

服务器代码:

#include "stdafx.h"
#include<stdio.h>
#include<WinSock2.h>
#pragma comment (lib,"ws2_32.lib")

DWORD WINAPI UDPCONN(LPVOID x)
{
    SOCKET s=(SOCKET)x;
    char bro[200]="I am SERVER";
    struct sockaddr_in hum;
    hum.sin_family=AF_INET;
    hum.sin_addr.s_addr=INADDR_BROADCAST;
    hum.sin_port=htons(8888);
    while (1)
    {
        if(sendto(s,bro,sizeof(bro),0,(struct sockaddr *)&hum,sizeof(hum))==SOCKET_ERROR)
        {
            printf("\nBroadcast failed ERROR CODE : %d\n",WSAGetLastError());
            exit(1);
        }
    }
 }

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKET s;
    struct sockaddr_in hum;
    int opt=1;

    //Initializing winsock2
    WSADATA wsa;
    if((WSAStartup(MAKEWORD(2,2),&wsa))!=0)
    {
        printf("\nWinsock Not initialized ERROR CODE : %d\n",WSAGetLastError());
        return 1;
    }

    //UDP Socket Creation
    if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
    {
        printf("\nUDP Socket not created ERROR CODE : %d\n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //socket defenition
    hum.sin_family=AF_INET;
    hum.sin_addr.s_addr=INADDR_ANY;
    hum.sin_port=htons(8888);

    //Broadcast permission
    if((setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char *)&opt,sizeof(opt)))<0)
    {
        printf("\nBroadcast permissions failed ERROR CODE : %d\n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //UDP SOCKET Binding 
    if((bind(s,(sockaddr *)&hum,sizeof(hum)))==SOCKET_ERROR)
    {
        printf("\nUDP socket binding failed ERROR CODE :%d\n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //UDP connection thread
    DWORD th;
    CreateThread(NULL,0,UDPCONN,(LPVOID)s,0,&th);

客户代码:

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    //UDP Data
    int slen;
    char message[300];
    int opt=1;
    SOCKET s;
    struct sockaddr_in sent;

    //Initializing winsock
    WSADATA wsa;
    if((WSAStartup(MAKEWORD(2,2),&wsa))!=0)
    {
        printf("\nFailed Initializing Winsock EROR CODE : %d\n",WSAGetLastError());
        return 1;
    }

    //UDP Socket creation
    if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))== SOCKET_ERROR)
    {
        printf("\nUDP socket creation failed ERROR CODE :%d\n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //UDP Broadcast permissions
    if((setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char *)&opt,sizeof(opt)))<0)
    {
        printf("\nERROR in broadcasting ERROR CODE : %d \n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //UDP socket definition
    sent.sin_family=AF_INET;
    sent.sin_addr.s_addr=INADDR_ANY;
    sent.sin_port=htons(8888);

    //UDP Receiving broadcasted data
    slen=sizeof(sent);
    //fflush(stdout);
    memset(message,'[=11=]',300);
    if((recvfrom(s,message,sizeof(message),0,(struct sockaddr *)&sent,&slen))<0)
    {
        printf("\nUDP Broadcast not received ERROR CODE : %d\n",WSAGetLastError());
        WSACleanup();
        return 1;
    }
    puts("\nGot server broadcast\n");
    puts("\nTracing server ip\n");
    getpeername(s,(sockaddr *)&sent,&slen);

    ...
}

这里我的客户抛出一个错误

UDP Broadcast not received ERROR CODE : 10022

错误代码 10022 的描述:参数无效。

提供了一些无效参数(例如,为 setsockopt 函数指定了无效级别)。在某些情况下,它还指套接字的当前状态——例如,在未侦听的套接字上调用 accept。

根据错误描述,recvfrom() 函数中的参数之一无效。但是我找不到无效的参数。

请帮我清除错误。

如果您阅读 recvfrom() documentation,它会确切地告诉您为什么您的客户端代码会出现错误:

Parameters

s [in]
A descriptor identifying a bound socket.

...

WSAEINVAL
The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, or (for byte stream-style sockets only) len was zero or negative.

您没有在调用 recvfrom() 之前在套接字上调用 bind()。更重要的是,当客户端和服务器 运行 在同一台机器上时,您不能将它们 bind() 连接到相同的 IP/port。更改您广播到的端口,然后让客户端绑定到该端口。

此外,recvfrom() 的最后两个参数为您提供了数据报发送方的 IP/Port。它们不是用于指定网络适配器来读取数据报。在这种情况下您不需要使用 getpeername()

您的代码还有一些其他问题:

在客户端,socket() returns INVALID_SOCKET 失败,而不是 SOCKET_ERROR

在服务器端,你真的不应该使用 INADDR_BROADCAST。您应该 bind() 将服务器套接字连接到特定的网络适配器,然后 sendto() 其特定的子网广播 IP,您可以使用 GetAdaptersInfo()GetAdaptersAddresses().

进行计算

而且两边都不能用WSAGetLastError()如果WSAStartup()失败,所以直接WSAStartup()returns错误码。在调用 WSACleanup();

之前你没有关闭套接字

试试这个:

服务器代码:

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment (lib,"ws2_32.lib")

DWORD WINAPI UDPCONN(LPVOID x)
{
    SOCKET s = (SOCKET)x;
    char bro[200] = "I am SERVER";
    struct sockaddr_in hum;

    memset(&hum, 0, sizeof(addr));
    hum.sin_family = AF_INET;
    hum.sin_addr.s_addr = INADDR_BROADCAST; // TODO: replace with subnet broadcast IP
    hum.sin_port = htons(8887);

    while (1)
    {
        if (sendto(s, bro, sizeof(bro), 0, (struct sockaddr *)&hum, sizeof(hum)) == SOCKET_ERROR)
        {
            printf("\nBroadcast failed ERROR CODE : %d\n", WSAGetLastError());
            return 1;
        }
    }

    return 0;
 }

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKET s;
    struct sockaddr_in hum;
    int err, opt=1;

    //Initializing winsock2
    WSADATA wsa;
    err = WSAStartup(MAKEWORD(2,2), &wsa);
    if (err != 0)
    {
        printf("\nWinsock Not initialized ERROR CODE : %d\n", err);
        return 1;
    }

    //UDP Socket Creation
    s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == INVALID_SOCKET)
    {
        printf("\nUDP Socket not created ERROR CODE : %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    //socket defenition
    memset(&hum, 0, sizeof(hum));
    hum.sin_family = AF_INET;
    hum.sin_addr.s_addr = INADDR_ANY; // TODO: replace with a specific NIC IP
    hum.sin_port = htons(8888);

    //Broadcast permission
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) == SOCKET_ERROR)
    {
        printf("\nBroadcast permissions failed ERROR CODE : %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    //UDP SOCKET Binding 
    if (bind(s, (sockaddr *)&hum, sizeof(hum)) == SOCKET_ERROR)
    {
        printf("\nUDP socket binding failed ERROR CODE : %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    //UDP connection thread
    DWORD th;
    HANDLE hThread = CreateThread(NULL,0, UDPCONN, s, 0, &th);
    if (!hThread)
    {
        printf("\nUDP thread failed ERROR CODE : %u\n", GetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    // do other things, wait for thread to terminate ...

    DWORD exitCode = 0;
    GetExitCodeThread(hThread, &exitCode);
    CloseHandle(hThread);

    closesocket(s);
    WSACleanup();

    return exitCode;
}

客户代码:

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    //UDP Data
    int addrlen, msglen;
    char message[300];
    int err, opt=1;
    SOCKET s;
    struct sockaddr_in hum, addr;

    //Initializing winsock
    WSADATA wsa;
    err = WSAStartup(MAKEWORD(2,2), &wsa);
    if (err != 0)
    {
        printf("\nFailed Initializing Winsock EROR CODE : %d\n", err);
        return 1;
    }

    //UDP Socket creation
    s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == INVALID_SOCKET)
    {
        printf("\nUDP socket creation failed ERROR CODE : %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    //UDP Broadcast permissions
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) == SOCKET_ERROR)
    {
        printf("\nERROR in broadcasting ERROR CODE : %d \n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    //UDP socket definition
    memset(&hum, 0, sizeof(addr));
    hum.sin_family = AF_INET;
    hum.sin_addr.s_addr = INADDR_ANY;
    hum.sin_port = htons(8887);

    //UDP SOCKET Binding 
    if (bind(s, (sockaddr *)&hum, sizeof(hum)) == SOCKET_ERROR)
    {
        printf("\nUDP socket binding failed ERROR CODE : %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    //UDP Receiving broadcasted data
    addrlen = sizeof(addr);
    msglen = recvfrom(s, message, sizeof(message), 0, (struct sockaddr *)&addr, &addrlen);
    if (msglen == SOCKET_ERROR)
    {
        printf("\nUDP Broadcast not received ERROR CODE : %d\n", WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

    printf("\nGot server broadcast\n");
    printf("\nServer ip: %s, port: %hu\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    printf("\nMessage: %.*s\n", msglen, message);

    ...
}

我尝试从服务器发送广播并从客户端接收广播的任何方法都无法有效地工作。

相反,我做了相反的事情,即从客户端发送广播来搜索工作正常的服务器。

这是我修改后的代码。

服务器代码:

#include "stdafx.h"
#include<stdio.h>
#include<WinSock2.h>
#pragma comment (lib,"ws2_32.lib")

DWORD WINAPI UDPCONN(LPVOID x)
{

SOCKET s=(SOCKET)x;
struct sockaddr_in server;
int len;
char buf[500]=("I am server");

char message[500];
len=sizeof(server);

int opt=1;

if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
{
    printf("\nSocket creation failed. ERROR CODE : %d\n",WSAGetLastError());
    WSACleanup();
    ExitThread(NULL);
}

server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=htons(8888);

if(setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char *)&opt,sizeof(opt))<0)
{
    printf("\nSetting broadcast failed : %d\n",WSAGetLastError());
    WSACleanup();
    ExitThread(NULL);
}
if((bind(s,(sockaddr *)&server,sizeof(server)))==SOCKET_ERROR)
{
    printf("\nBind failed. ERROR CODE : %d\n",WSAGetLastError());
    WSACleanup();
    ExitThread(NULL);
}

while(1)
{

    fflush(stdout);
     memset(message,'[=10=]', 500);
    //try to receive some data, this is a blocking call
    if (recvfrom(s, message, 500, 0, (struct sockaddr *) &server,&len) == SOCKET_ERROR)
    {
        printf("recvfrom() failed with error code : %d" , WSAGetLastError());
        ExitThread(NULL);
    }

    if(sendto(s,buf,sizeof(buf),0,(struct sockaddr *)&server,sizeof(server))==SOCKET_ERROR)
    {
        printf("\nIP Broadcast failed ERROR code : %d\n",WSAGetLastError());
        WSACleanup();
        ExitThread(NULL);
    }
 }

}
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET s;
//struct sockaddr_in hum;
int opt=1;
//Initializing winsock2
WSADATA wsa;
if((WSAStartup(MAKEWORD(2,2),&wsa))!=0)
{
    printf("\nWinsock Not initialized ERROR CODE : %d\n",WSAGetLastError());
    return 1;
}
s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

//UDP connection thread
DWORD th;
CreateThread(NULL,0,UDPCONN,(LPVOID)s,0,&th);
closesocket(s);

客户代码:

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
//UDP Data
int slen;
char message[600];
char buf[300]=("Hai server");
int opt=1;
SOCKET s;
struct sockaddr_in sent;

//TCP Connection data
SOCKET t;
struct sockaddr_in server;
char messag[300],server_reply[300];
int recv_size;


//Initializing winsock
WSADATA wsa;
if((WSAStartup(MAKEWORD(2,2),&wsa))!=0)
{
    printf("\nFailed Initializing Winsock EROR CODE : %d\n",WSAGetLastError());
    return 1;
}

//UDP Socket creation
if((s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))== INVALID_SOCKET)
{
    printf("\nUDP socket creation failed ERROR CODE :%d\n",WSAGetLastError());
    WSACleanup();
    return 1;
}

//UDP Broadcast permissions
if((setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char *)&opt,sizeof(opt)))<0)
    {
        printf("\nERROR in broadcasting ERROR CODE : %d \n",WSAGetLastError());
        WSACleanup();
        return 1;
    }

//UDP socket definition
sent.sin_family=AF_INET;
sent.sin_addr.s_addr=INADDR_BROADCAST;
sent.sin_port=htons(8888);

if (sendto(s, buf, sizeof(buf) , 0 , (struct sockaddr *) &sent,sizeof(sent)) == SOCKET_ERROR)
    {
        printf("sendto() failed with error code : %d" , WSAGetLastError());
        exit(EXIT_FAILURE);
    }

//UDP Receiving broadcasted data
slen=sizeof(sent);
fflush(stdout);
memset(message,'[=11=]',300);
if((recvfrom(s,message,sizeof(message),0,(struct sockaddr *)&sent,&slen))<0)
{
    printf("\nUDP Broadcast not received ERROR CODE : %d\n",WSAGetLastError());
    WSACleanup();
    return 1;
}
puts("\nGot server broadcast\n");
puts("\nTracing server ip\n");
getpeername(s,(sockaddr *)&sent,&slen);
closesocket(s);

此处的两个代码在 visual studio 2012 中都可以正常工作。 这也只是我整个大计划的一部分。但是这部分仍然可以独立工作。

所以在发表负面评论之前,请确保您编译并 运行 程序。