UDP协议 sendto 和 recvfrom 浅析与示例

本文详细介绍了UDP(用户数据报协议)的工作原理,强调其非连接性和高效性,并展示了如何使用C++编写简单的UDP服务端和客户端程序。服务端包括创建套接字、绑定端口、接收和发送数据,而客户端则负责发送数据和接收响应。通过示例代码,读者可以了解UDP通信的基本流程。
摘要由CSDN通过智能技术生成

图片/在思考的樱木花道

UDP(user datagram protocol)用户数据报协议,属于传输层。

UDP是面向非连接的协议,它不与对方建立连接,而是直接把数据报发给对方。UDP无需建立类如三次握手的连接,使得通信效率很高。因此UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。

UDP通信的过程:

服务端:

(1)使用函数socket(),生成套接字文件描述符;

(2)通过struct sockaddr_in 结构设置服务器地址和监听端口;

(3)使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;

(4)接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;

(5)向客户端发送数据,使用sendto() 函数向服务器主机发送数据;

(6)关闭套接字,使用close() 函数释放资源;

客户端:

(1)使用socket(),生成套接字文件描述符;

(2)通过struct sockaddr_in 结构设置服务器地址和监听端口;

(3)向服务器发送数据,sendto() ;

(4)接收服务器的数据,recvfrom() ;

(5)关闭套接字,close() ;

  • sockaddr 与 sockaddr_in 区别

https://blog.csdn.net/qingzhuyuxian/article/details/79736821

sendto()

1 1 int sendto(int s, const void *buf, int len, unsigned int flags, 
2         const struct sockaddr *to, int tolen);

返回值说明:

成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。

参数说明:

  • s:     socket描述符;

  • buf:UDP数据报缓存区(包含待发送数据);

  • len:  UDP数据报的长度;

  • flags:调用方式标志位(一般设置为0);

  • to:  指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);

  • tolen:to所指结构体的长度;

recvfrom()

1 int recvfrom(int s, void *buf, int len, unsigned int flags,
2           struct sockaddr *from, int *fromlen); 

返回值说明:

成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。

参数说明:

  • s:         socket描述符;

  • buf:      UDP数据报缓存区(包含所接收的数据);

  • len:      缓冲区长度。

  • flags:   调用操作方式(一般设置为0)。

  • from:    指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);

  • fromlen:指针,指向from结构体长度值。

示例代码

服务端

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define MAXLINE 4096
#define UDPPORT 8001
#define SERVERIP "192.168.255.129"

using namespace std;

int main(){
    int serverfd;
    unsigned int server_addr_length, client_addr_length;
    char recvline[MAXLINE];
    char sendline[MAXLINE];
    struct sockaddr_in serveraddr , clientaddr;

    // 使用函数socket(),生成套接字文件描述符;
    if( (serverfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){
        perror("socket() error");
        exit(1);
    }

    // 通过struct sockaddr_in 结构设置服务器地址和监听端口;
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(UDPPORT);
    server_addr_length = sizeof(serveraddr);

    // 使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;
    if( bind(serverfd, (struct sockaddr *) &serveraddr, server_addr_length) < 0){
        perror("bind() error");
        exit(1);
    }

    // 接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;
    client_addr_length = sizeof(sockaddr_in);
    int recv_length = 0;
    recv_length = recvfrom(serverfd, recvline, sizeof(recvline), 0, (struct sockaddr *) &clientaddr, &client_addr_length);
    cout << "recv_length = "<< recv_length <<endl;
    cout << recvline << endl;

    // 向客户端发送数据,使用sendto() 函数向服务器主机发送数据;
    int send_length = 0;
    sprintf(sendline, "hello client !");
    send_length = sendto(serverfd, sendline, sizeof(sendline), 0, (struct sockaddr *) &clientaddr, client_addr_length);
    if( send_length < 0){
        perror("sendto() error");
        exit(1);
    }
    cout << "send_length = "<< send_length <<endl;

    //关闭套接字,使用close() 函数释放资源;
    close(serverfd);

    return 0;
}

客户端

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define MAXLINE 4096
#define UDPPORT 8001
#define SERVERIP "192.168.255.129"

using namespace std;

int main(){
    int confd;
    unsigned int addr_length;
    char recvline[MAXLINE];
    char sendline[MAXLINE];
    struct sockaddr_in serveraddr;

    // 使用socket(),生成套接字文件描述符;
    if( (confd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){
        perror("socket() error");
        exit(1);
    }

    //通过struct sockaddr_in 结构设置服务器地址和监听端口;
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(SERVERIP);
    serveraddr.sin_port = htons(UDPPORT);
    addr_length = sizeof(serveraddr);

    // 向服务器发送数据,sendto() ;
    int send_length = 0;
    sprintf(sendline,"hello server!");
    send_length = sendto(confd, sendline, sizeof(sendline), 0, (struct sockaddr *) &serveraddr, addr_length);
    if(send_length < 0 ){
        perror("sendto() error");
        exit(1);
    }
    cout << "send_length = " << send_length << endl;

    // 接收服务器的数据,recvfrom() ;
    int recv_length = 0;
    recv_length = recvfrom(confd, recvline, sizeof(recvline), 0, (struct sockaddr *) &serveraddr, &addr_length);
    cout << "recv_length = " << recv_length <<endl;
    cout << recvline << endl;

    // 关闭套接字,close() ;
    close(confd);

    return 0;
}

文章转自:


https://www.cnblogs.com/HpeMephisto/p/11312193.html


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

嵌入式Linux

微信扫描二维码,关注我的公众号

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值