使用SOCK_DGRAM从服务器获取信息时出现问题

时间:2010-12-09 02:52:52

标签: c linux sockets

我有以下程序(DGRAM套接字)从时间服务器中检索时间。该程序不会按预期打印出当前时间。

#define DAYTIME_SERVER_PORT  13

int main(int argc, char *argv[])
{

    int connectionFd, in;
    struct sockaddr_in servaddr;
    char buf[BUFSIZ];

    connectionFd = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(DAYTIME_SERVER_PORT);
    inet_pton(AF_INET,"time.mit.edu", &servaddr.sin_addr);

    sendto( connectionFd,buf ,1, 0,(struct sockaddr_in *)&servaddr, sizeof(servaddr) );

    in = recv(connectionFd, buf, BUFSIZ, 0 ) ; 
    buf[in] = 0 ; 
    printf("Time is %s \n",buf);

    close(connectionFd);


}

我的问题是 - 我在哪里弄错了?任何代码更改和宝贵的建议表示赞赏。我不知道如何使用recvform函数,因此尝试了recv。我要连接的日间服务器是time.mit.edu

3 个答案:

答案 0 :(得分:9)

inet_pton()不会查找time.mit.edu等主机名。它仅用于将IP地址的字符串形式(如"18.7.21.144")转换为套接字地址。

您应该使用getaddrinfo()来查找"time.mit.edu"之类的名称。它还可以完成查找daytime端口号的工作。您的代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
    struct addrinfo *addr;
    struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM };
    int err;
    int connectionFd, in;
    char buf[1024];

    err = getaddrinfo("time.mit.edu", "daytime", &hints, &addr);
    if (err) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
        return 1;
    }

    connectionFd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);

    sendto(connectionFd, "." , 1, 0, addr->ai_addr, addr->ai_addrlen );

    freeaddrinfo(addr);

    in = recv(connectionFd, buf, sizeof buf - 1, 0 ) ;
    buf[in] = 0 ;
    printf("Time is %s \n",buf);

    close(connectionFd);
    return 0;
}

(看,马云:支持IPv6的白天;)

当然,您还应该检查socket()sendto()recv()的返回值,就像我对getaddrinfo()所做的那样。特别要考虑如果recv()失败并返回-1 ...

会发生什么

答案 1 :(得分:2)

您既不会检查socket(2)sendto(2)的返回值,也不会检查-1函数的返回值,这些函数会在出错时返回recv()并设置全局recv(2)变量。养成总是检查系统调用返回的习惯。

您将BUFSIZ BUFSIZ作为可用空间,然后在收到的长度后写入字节1。如果2^16非常大(比任何UDP数据报都大,即buf),这可能不是真正的问题,但是如果你收到完整的{{1}},你可能会超越缓冲区 - 值得数据

至于你代码中的真正问题 - @caf已经回答了这个问题。

答案 2 :(得分:0)

您的代码基本上是正确的。我不得不稍微调整它,因为我正在运行Windows,但它对我有用。所以这里有一些你可以看到的东西:

  • sendto的返回值是多少?这可能至少告诉你是否正在连接OK。

  • 检查您的地址是否正确。将time.mit.edu的IP地址直接硬编码到servaddr.sin_addr可能更容易,以消除inet_pton导致问题的任何可能性。

  • BUFSIZ的价值是多少?通常它是在stdio.h中设置的,但你确定它不是以某种方式为零吗?

  • 您没有将协议明确设置为IPPROTO_UDP。这通常是正常的,因为当您设置protocol = 0时,套接字库将选择适当的协议。使用getsockopt(SO_PROTOCOL_INFO)检查它是否正确(或在调用socket()时明确设置它。)

  • 您的防火墙是否妨碍了?尝试telneting到time.mit.edu:13。它应该打印出时间然后关闭连接。

关于recvfrom ...它与recv相同,只是它捕获了对等主机的地址。这种差异在这里并不重要。