C语言中的UDP套接字

5
我正在为课程做一道作业题。我想启动一个UDP服务器,用于侦听文件请求。它会打开文件并通过UDP将其发送回请求的客户端。
以下是服务器代码:
    // Create UDP Socket
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Can't create socket");
        exit(-1);
    }

    // Configure socket
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET; // Use IPv4
    server.sin_addr.s_addr = htonl(INADDR_ANY); // My IP
    server.sin_port = htons(atoi(argv[1])); // Server Port

    // Bind socket
    if ((bind(sockfd, (struct sockaddr *) &server, sizeof(server))) == -1) {
        close(sockfd);
        perror("Can't bind");
    }

    printf("listener: waiting to recvfrom...\n");
    if (listen(sockfd, 5) == -1) {
        perror("Can't listen for connections");
        exit(-1);
    }

while (1) {
    client_len = sizeof(struct sockaddr_in);
    newsockfd = accept(sockfd, (struct sockaddr*)&client,&client_len);

    if (newsockfd < 0) {
        perror("ERROR on accept");
    }

    // Some how parse request
    // I do I use recv or recvfrom?
    // I do I make new UDP socket to send data back to client?

    sendFile(newsockfd, filename);

    close(newsockfd);
}

close(sockfd);

我有点迷茫,如何从客户端接收数据?如何与客户端建立新的UDP连接?


1
你应该参考Beej's Guide to Network Programming。它详细介绍了网络编程的基础知识。第5章涵盖了系统调用,其中包括有关recvrecvfrom的信息。 - James McNellis
4个回答

13

我用C语言编写了一个UDP服务器-客户端,其中客户端发送一个注册号码,服务器以名称作为反馈。

服务器

0. Variable initialization
1. sock()
2. bind()
3. recvfrom()
4. sendto()

客户端

0. gethostbyname()
1. sock()
2. bzero()
4. sendto()
5. recvfrom()

希望这有所帮助。您可以在这里找到示例代码,UDP服务器/客户端。


13

UDP与TCP的区别:

  • 面向消息,而不是面向流。你不需要读/写或发送/接收,而是使用sendto/recvfrom。消息的大小限制为64K。每次调用recvfrom都会得到一个由sendto调用发送的消息。如果recvfrom传递的缓冲区小于消息的大小,则剩余的消息将永远丢失。

  • 没有连接。因此没有listen/accept/connect。你向特定的地址/端口发送消息。当你接收到消息(在你的套接字绑定的地址/端口上),你可以通过recvfrom的输出参数获取传入消息的源。

  • 没有保证。消息可能会被丢弃或乱序接收。虽然我记得它们不能被截断。

最后一句话提醒 - 你可能会发现自己在UDP上重新发明TCP。在这种情况下,请停止并返回TCP。


这就是重点。它不是对TCP的完全重新发明,只是RDT,没有拥塞控制或TCP的任何其他功能。 - Bernie Perez
请确保您不需要放弃TCP的功能。 - user3458
connect 对于 UDP 是可以的。您可以使用它来设置 send/write 的默认目标,而不是使用 sendto - EML

2

accept仅用于面向连接的(STREAM)套接字。UDP不是面向流的,因此没有连接,不能使用accept(2)-它将返回EOPNOTSUPP。

相反,您可以直接从绑定的服务套接字读取数据包(通常使用recvfrom(2),以便您知道它们来自哪里,但如果您不关心,也可以使用recv或just read),之后您可以使用相同的套接字发送数据包(通常使用sendto(2))


谢谢,这对我的问题非常有帮助。如果没有人有一个好的例子可以跟随,那么这将是被接受的答案。 - Bernie Perez

1
请记住,UDP是无连接的。它只发送数据包,不适合发送文件 - 除非整个内容适合一个UDP数据包。
如果您仍然想要发送/接收UDP数据包,只需使用适当的地址调用sendto/recvfrom即可。

下一步是将文件分成多个部分,并使用SR或GBN发送。 - Bernie Perez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接