Linux网络编程- recvfrom() & sendto()

recvfrom()

recvfrom() 函数是一个系统调用,用于从套接字接收数据。该函数通常与无连接的数据报服务(如 UDP)一起使用,但也可以与其他类型的套接字使用。与简单的 recv() 函数不同,recvfrom() 可以返回数据来源的地址信息。

函数原型为:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

参数解释:

  1. sockfd:一个已打开的套接字的描述符。

  2. buf:一个指针,指向用于存放接收到的数据的缓冲区。

  3. len:缓冲区的大小(以字节为单位)。

  4. flags:控制接收行为的标志。通常可以设置为0,但以下是一些可用的标志:

    • MSG_WAITALL:尝试接收全部请求的数据。函数可能会阻塞,直到收到所有数据。
    • MSG_PEEK:查看即将接收的数据,但不从套接字缓冲区中删除它【1】。
    • 其他一些标志还可以影响函数的行为,但在大多数常规应用中很少使用。
  5. src_addr:一个指针,指向一个 sockaddr 结构,用于保存发送数据的源地址。

  6. addrlen:一个值-结果参数。开始时,它应该设置为 src_addr 缓冲区的大小。当 recvfrom() 返回时,该值会被修改为实际地址的长度(以字节为单位)。

返回值:

  • 在成功的情况下,recvfrom() 返回接收到的字节数。
  • 如果没有数据可读或套接字已经关闭,那么返回值为0。
  • 出错时,返回 -1,并设置全局变量 errno 以指示错误类型。

例子:

struct sockaddr_in sender;
socklen_t sender_len = sizeof(sender);
char buffer[1024];

int bytes_received = recvfrom(sockfd, buffer, sizeof(buffer), 0,
                              (struct sockaddr*)&sender, &sender_len);
if (bytes_received < 0) {
    perror("recvfrom failed");
    // handle error
}

在这个例子中,我们使用 recvfrom() 从套接字 sockfd 接收数据。发送者的地址和端口信息保存在 sender 结构中。

sendto()

sendto() 函数是一个系统调用,用于发送数据到一个指定的地址。它经常与无连接的数据报协议,如UDP,一起使用。不像 send() 函数只能发送数据到一个预先建立连接的远端,sendto() 允许在每次发送操作时指定目的地址。

函数原型为:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

参数解释:

  1. sockfd:一个已打开的套接字的描述符。

  2. buf:一个指针,指向要发送的数据的缓冲区。

  3. len:要发送的数据的大小(以字节为单位)。

  4. flags:控制发送行为的标志。通常可以设置为0。一些可用的标志包括:

    • MSG_CONFIRM:在数据报协议下告诉网络层该数据已经被确认。
    • MSG_DONTROUTE:不查找路由,数据报将只发送到本地网络。
    • 其他标志可以影响函数的行为,但在大多数常规应用中很少使用。
  5. dest_addr:指向 sockaddr 结构的指针,该结构包含目标地址和端口信息。

  6. addrlendest_addr 缓冲区的大小(以字节为单位)。

返回值:

  • 成功时,sendto() 返回实际发送的字节数。
  • 出错时,返回 -1 并设置全局变量 errno 以指示错误类型。

例子:

struct sockaddr_in receiver;
receiver.sin_family = AF_INET;
receiver.sin_port = htons(12345);  // Some port number
inet_pton(AF_INET, "192.168.1.1", &receiver.sin_addr);  // Some IP address

char message[] = "Hello, World!";
ssize_t bytes_sent = sendto(sockfd, message, sizeof(message), 0,
                            (struct sockaddr*)&receiver, sizeof(receiver));
if (bytes_sent < 0) {
    perror("sendto failed");
    // handle error
}

在这个例子中,我们使用 sendto() 发送一个字符串到指定的IP地址和端口号。如果发送失败,我们打印一个错误消息。


注1

让我们通过一个简单的示例来展示如何使用MSG_PEEK标志来窥探套接字中的数据。

假设场景:我们正在编写一个简单的TCP服务器,该服务器接收客户端发送的消息。这些消息由一个头部开始,表示随后的数据长度。我们希望窥探这个头部,以便知道接下来应该读取多少数据。

假设消息头部长度固定为4字节,表示数据的长度。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#define PORT 8080
#define HEADER_SIZE 4

int main() {
    int server_socket, client_socket;
    struct sockaddr_in address;
    int addr_len = sizeof(address);
    char buffer[1024];

    // 创建TCP套接字
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 绑定套接字到指定的端口
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    if (bind(server_socket, (struct sockaddr*)&address, sizeof(address)) == -1) {
        perror("bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    // 开始监听
    if (listen(server_socket, 3) == -1) {
        perror("listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    printf("Waiting for a connection...\n");
    client_socket = accept(server_socket, (struct sockaddr*)&address, (socklen_t*)&addr_len);
    if (client_socket == -1) {
        perror("accept failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
    printf("Connection established.\n");

    // 窥探消息头部
    int peek_len = recv(client_socket, buffer, HEADER_SIZE, MSG_PEEK);
    if (peek_len != HEADER_SIZE) {
        printf("Failed to peek header\n");
        close(client_socket);
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    // 假设头部数据是一个整数,表示接下来的消息长度
    int message_len = *((int*)buffer);
    printf("Expected message length: %d\n", message_len);

    // 现在,可以根据消息长度读取整个消息

    close(client_socket);
    close(server_socket);
    return 0;
}

这只是一个简化的示例,实际应用中还需要考虑其他方面,如错误处理、多个客户端的处理、消息头和数据的解析等。


【1】若想了解sockaddr_in结构体,可移步到

     Linux网络编程- sockaddr & sockaddr_in & in_addr

【2】若想了解常用的网络编程函数,可移步到

     Linux- 网络编程初探

  • 33
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嵌入式Linux网络编程可以通过使用Socket编程来实现。Socket编程是一种在网络上进行通信的基本方法,它使用一系列的函数来创建、连接、发送和接收数据。 首先,你需要在嵌入式Linux上编译你的程序。以ARM为例,你可以使用以下命令来编译你的程序: 接下来,你需要使用Socket编程的基本函数来实现网络通信。这些基本函数包括socket、bind、listen、accept、sendsendto、recvrecvfrom。其中,socket函数用于创建一个套接字,bind函数用于将套接字绑定到一个特定的IP地址和端口,listen函数用于监听套接字上的连接请求,accept函数用于接受连接请求并创建一个新的套接字来处理连接,sendsendto函数用于发送数据,recvrecvfrom函数用于接收数据。 在嵌入式Linux上,你可以使用以下命令来编译你的程序: gcc clientsdl.c -lpthread -o clientsdl -I/usr/local/include -L/usr/local/lib -lSDL -lSDL_image -lSDL_gfx 通过使用这些基本函数和编译命令,你可以在嵌入式Linux上实现网络编程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [嵌入式Linux网络编程](https://blog.csdn.net/wjky2014/article/details/8488146)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫客36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值