【问题标题】:No idea how to get server address in subnetwork UDP sockets c不知道如何在子网 UDP 套接字 c 中获取服务器地址
【发布时间】:2014-06-04 18:05:04
【问题描述】:

我有一个问题:

有什么方法可以从客户端的角度通过广播发现服务器地址?

我几乎阅读了 Internet 上的所有内容,但没有任何信息可以告诉我如何在不知道其名称的情况下发现服务器地址 (gethostbyname())。我需要使用 UDP 创建一个客户端-服务器应用程序,服务器发送广播,客户端应该发现它并将一些文本发回给它。

据我所知,客户端需要创建一个套接字,然后通过 gethostbyname() 获取主机(服务器)地址,以便获得可以在其上进行 recvfrom() 的地址,然后执行即 sendto()。

基本上,服务器仅使用端口(命令行参数)启动,在该端口上创建其套接字和 bind(),客户端也仅使用端口(命令行参数)启动,并且应该通过广播发现服务器地址。这是我目前所拥有的:

服务器:

   struct sockaddr_in addr;
    int socketfd,t=1;
    socketfd = make_socket(PF_INET,type);
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&t, sizeof(t))) ERR("setsockopt");
    if(bind(socketfd,(struct sockaddr*) &addr,sizeof(addr)) < 0)  ERR("bind");

然后我想将它从服务器广播到子网中的任何地方,但不知道为什么:(

客户:

struct sockaddr_in addr;
    struct hostent *hostinfo;
    addr.sin_family = AF_INET;
    addr.sin_port = htons (port);
    hostinfo = gethostbyname(address);
    if(hostinfo == NULL)HERR("gethostbyname");
    addr.sin_addr = *(struct in_addr*) hostinfo->h_addr;

在这里,我想以某种方式接收服务器广播的内容并发回一些文本。

编辑: 我会这样做:

int fd;
struct sockaddr_in addr;

fd = socket(PF_INET, SOCK_DGRAM, 0);

char buf[TEXT_SIZE];
socklen_t size=sizeof(addr);

recvfrom(fd, (char *)buf, sizeof(char[FILE_SIZE]), 0, &addr, &size);

但是如何设置服务器广播它,以便上面代码的客户端可以接收它?我总是通过以下方式发送它:

sendto(fd, (char *)some_buffer, sizeof(some_buffer), 0, &addr, sizeof(addr));

但是我的服务器无法发现客户端addr,因为它必须首先将广播发送给所有客户端。所以我不能在这里填写addr,因为它还没有设置。服务器有什么方法可以在不知道客户端地址的情况下首先广播消息?服务器只创建一个套接字绑定它,然后需要立即广播一些文本。感谢您的回复。

【问题讨论】:

  • 使用 recvfrom 接收帧并获取发送者地址。
  • 也许这会有所帮助> stackoverflow.com/questions/8017803/…
  • "我几乎阅读了互联网上的所有内容..." 哇! ;-)
  • 您是否进行了建议的更改?

标签: c network-programming udp broadcast


【解决方案1】:

您对解决问题的方式存在困惑。

gethostbyname 将使用解析器根据提供的名称查找 IP 地址。因此,您需要提供服务器名称并在某处进行映射:它可能是 hosts 文件中的相应条目,也可能是 DNS 服务器中的 A(或 AAAA)记录。

但是从你的问题描述来看,似乎你并不想使用gethostbyname来获取服务器IP地址。

如果服务器正在广播 UDP 数据报,并且您的客户端知道它正在广播的端口,则客户端可以读取 UDP 数据报并获取源地址。

顺便说一句,您显示的服务器代码未发送广播。

这看起来像是网络课程的练习。

【讨论】:

  • 感谢您的回复。'如果服务器正在广播 UDP 数据报,并且您的客户端知道它正在广播的端口,则客户端可以读取 UDP 数据报并获取源地址。我如何在知道服务器广播到的端口的客户端中读取这些广播?因为当我只是尝试 recvfrom (在客户端)来获取服务器的地址时,客户端永远挂起。在客户端中,我创建了一个套接字,然后立即尝试 recvfrom 并且客户端挂起..
  • 如果您为客户复制整个代码,您会为我提供更多帮助。如果您拥有帖子中显示的代码,那将无法正常工作。您在那里缺少一些 addr 字段。请问,你能正确复制你的代码而不是各种单独的sn-ps吗?
  • @Christopher_Programmer_Wannabe,我看到代码了,请将端口类型改为short int。
  • @Christopher_Programmer_Wannabe,我看到代码了,请将端口类型改为short int。在客户端和服务器中。在客户端,将socket client_socket绑定到端口和地址,定义另一个struct sockaddr_in(不同于addr),将其置零,并设置对应的值:sin_family, sin_addr, sin_port ...
【解决方案2】:

这里是代码。我假设服务器正在发送广播,而客户端在 recvfrom 上挂起,希望您知道如何解决此问题,谢谢。

服务器:

#define _GNU_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <fcntl.h>
#include <dirent.h>
#include <arpa/inet.h>
#define ERR(source) (perror(source),\
             fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
             exit(EXIT_FAILURE))

int main(int argc, char **argv)
{
    if(argc != 2)
    {
        return EXIT_FAILURE;
    }

    int port = atoi(argv[1]);

    struct sockaddr_in addr;
    int server_socket, t = 1;
    socklen_t size = sizeof(addr);

    server_socket = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&addr, 0, sizeof(struct sockaddr_in));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST ,&t, sizeof(t)))
        ERR("setsockopt");

    if(bind(server_socket,(struct sockaddr*) &addr,sizeof(addr)) < 0) 
        ERR("bind");

    char buf[12] = "FromServer";

    /* I assume here I broadcast message assuming I set all attributes properly */
    if(sendto(server_socket, buf, sizeof(char[12]), 0, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        printf("problem");
        return EXIT_FAILURE;
    }

    printf("Sent to client: %s \n", buf);

    sleep(2);

    if(TEMP_FAILURE_RETRY(close(server_socket))<0)
        ERR("close");

    printf("\n\n----------------- Server [%d] terminated. -----------------  \n", getpid());    
    return EXIT_SUCCESS;
}

客户:

#define _GNU_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BACKLOG 10
#define ERR(source) (perror(source),\
             fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
             exit(EXIT_FAILURE))
#define HERR(source) (fprintf(stderr,"%s(%d) at %s:%d\n",source,h_errno,__FILE__,__LINE__),\
             exit(EXIT_FAILURE))

int main(int argc, char **argv)
{
    int client_socket;

    if(argc != 2)
    {
        return EXIT_FAILURE;
    }

    /* client port */
    int port = atoi(argv[1]);

    client_socket = socket(PF_INET, SOCK_DGRAM, 0);

    char data[12];

    struct sockaddr_in addr;
    socklen_t size = sizeof(addr);

    /* Here I would like to receive server broadcast (i.e. some text) but it hangs for ever */
    if(recvfrom(client_socket, (char *)data, sizeof(char[12]), 0, &addr, &size) < 0)
    {
        return EXIT_FAILURE;
    }

    printf("Received from server: %s \n", data);

    if(TEMP_FAILURE_RETRY(close(client_socket))<0)
        ERR("close");

    printf("\n\n----------------- Client [%d] terminated. -----------------  \n", getpid());    
    return EXIT_SUCCESS;
}

【讨论】:

  • 我在回复部分添加了我的 cmets。
  • 我看到代码了,请将端口类型改为short int。在客户端和服务器中。在客户端,将socket client_socket绑定到端口和地址,定义另一个struct sockaddr_in(不同于addr),将其置零,并设置对应的值:sin_family, sin_addr, sin_port ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-15
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多