当前位置: 代码网 > 服务器>服务器>Linux > Linux下使用C/C++进行UDP网络编程详解

Linux下使用C/C++进行UDP网络编程详解

2024年10月30日 Linux 我要评论
udp 是user datagram protocol 的简称,中文名是用户数据报协议,是一种无连接、不可靠的协议,同样它也是工作在传顺层。它只是简单地实现从一端主机到另一端主机的数据传输功能,这些数

udp 是user datagram protocol 的简称,中文名是用户数据报协议,是一种无连接、不可靠的协议,同样它也是工作在传顺层。它只是简单地实现从一端主机到另一端主机的数据传输功能,这些数据通过 ip 层发送,在网络中传输,到达目标主机的顺序是无法预知的,因此需要应用程序对这些数据进行排序处理,这就带来了很大的不方便,此外,udp 协议更没有流量控制、拥塞控制等功能,在发送的一端,udp 只是把上层应用的数据封装到udp 报文中,在差错检测方面,仅仅是对数据进行了简单的校验,然后将其封装到 ip 数据报中发送出去。而在接收端,无论是否收到数据,它都不会产生一个应答发送给源主机,并且如果接收到数据发送校验错误,那么接收端就会丢弃该udp 报文,也不会告诉源主机,这样子传输的数据是无法保障其准确性的,如果想要其准确性,那么就需要应用程序来保障了。

udp 协议的特点:

  • 无连接、不可靠;
  • 尽可能提供交付数据服务,出现差错直接丢弃,无反馈;
  • 面向报文,发送方的udp 拿到上层数据直接添加个udp 首部,然后进行校验后就递交给 ip 层而接收的一方在接收到udp 报文后简单进行校验,然后直接去除数据递交给上层应用;
  • 速度快,因为udp 协议没有tcp 协议的握手、确认、窗口、重传、拥塞控制等机制,udp 是一个无状态的传输协议,所以它在传递数据时非常快,即使在网络拥塞的时候udp 也不会降低发送的数据。 udp 虽然有很多缺点,但也有自己的优点,所以它也有很多的应用场合,因为在如今的网络环境下, udp 协议传输出现错误的概率是很小的,并且它的实时性是非常好,常用于实时视频的传输,比如直播、网络电话等,因为即使是出现了数据丢失的情况,导致视频卡帧,这也不是什么大不了的事情,所以,udp协议还是会被应用与对传输速度有要求,并且可以容忍出现差错的数据传输中。

在linux使用socket网络编程实现udp通信流程如下:

1.  初始化socket

int sock_fd = socket(af_inet , sock_dgram , 0); 
if(sock_fd < 0){
    perror("failed to open socket");
    return -1;
}

2.  绑定ip和端口号

/** 绑定ip和端口号 */ 
struct sockaddr_in server_addr;
server_addr.sin_family = af_inet;
server_addr.sin_addr.s_addr = inaddr_any; // 本地任意ip
server_addr.sin_port = htons(8888);       // 指定端口号
int ret = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret < 0)
{
    perror("failed to bind");
    close(sock_fd);
    return -1;
}

3. 设置组播接收(可选)

std::string multi_addr = "224.0.0.10";
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(multi_addr.c_str());
mreq.imr_interface.s_addr = inaddr_any;
ret = setsockopt(sock_fd, ipproto_ip, ip_add_membership, &mreq, sizeof(struct ip_mreq));
if (0 >ret)
{
    perror("set socket multicast error");
    return false;
}

4. 设置接收超时(可选)

/** 设置接收超时(可选) */
int mill_sec = 2000;  // 毫秒
struct timeval time_out;
time_out.tv_sec = mill_sec / 1000;
time_out.tv_usec = (mill_sec- time_out.tv_sec * 1000) * 1000;
ret = setsockopt(sock_fd, sol_socket,so_rcvtimeo,&time_out,sizeof (timeval));
if(ret < 0)
{
    perror("udp settimeout error!");
}

5.  发送数据

unsigned char buf[1024];
std::string ip = "192.168.1.10";
int port = 1234;
struct sockaddr_in client{};
memset(&client, 0, sizeof(client));
client.sin_addr.s_addr = inet_addr(ip.c_str());
client.sin_family = af_inet;
client.sin_port = htons(port);
ret = sendto(sock_fd, buf, sizeof(buf), 0, reinterpret_cast<struct sockaddr *>(&client), sizeof(struct sockaddr));
if(ret < 0){
    perror("udpserver send error!");
}else{
    std::cout << "send success!" << std::endl;
}

6. 接收数据

unsigned char buffer[1024];
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
while(true)
{
    memset(buffer, 0, sizeof(buffer));
    ssize_t len = recvfrom(sock_fd_, buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr *>(&addr), &addr_len);
    if(len > 0)
    {
        std::cout << "received message len : " << len << std::endl;
    }else{
        perror("recv error");
    }
}

7. 完整代码

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <thread>
 
void recv_func(int sock_fd_)
{
unsigned char buffer[1024];
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
while(true)
{
    memset(buffer, 0, sizeof(buffer));
    ssize_t len = recvfrom(sock_fd_, buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr *>(&addr), &addr_len);
    if(len > 0)
    {
        std::cout << "received message len : " << len << std::endl;
    }else{
        perror("recv error");
    }
}
}
 
int main(int agrc, char** argv)
{
    int sock_fd = socket(af_inet , sock_dgram , 0); 
    if(sock_fd < 0){
        perror("failed to open socket");
        return -1;
    }
 
    /** 绑定ip和端口号 */ 
    struct sockaddr_in server_addr;
    server_addr.sin_family = af_inet;
    server_addr.sin_addr.s_addr = inaddr_any; // 本地任意ip
    server_addr.sin_port = htons(8888);       // 指定端口号
    int ret = bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if(ret < 0)
    {
        perror("failed to bind");
        close(sock_fd);
        return -1;
    }
 
    /** 设置组播接收 (可选)*/
std::string multi_addr = "224.0.0.10";
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(multi_addr.c_str());
mreq.imr_interface.s_addr = inaddr_any;
ret = setsockopt(sock_fd, ipproto_ip, ip_add_membership, &mreq, sizeof(struct ip_mreq));
if (0 >ret)
{
    perror("set socket multicast error");
    return false;
}
 
/** 设置接收超时(可选) */
int mill_sec = 2000;  // 毫秒
struct timeval time_out;
time_out.tv_sec = mill_sec / 1000;
time_out.tv_usec = (mill_sec- time_out.tv_sec * 1000) * 1000;
ret = setsockopt(sock_fd, sol_socket,so_rcvtimeo,&time_out,sizeof (timeval));
if(ret < 0)
{
    perror("udp settimeout error!");
}
 
 
    /** 开启线程接收 */
    std::thread recv_t(recv_func, sock_fd);
    recv_t.detach();
 
    /** 主线程发送 */
    while (true)
    {
unsigned char buf[1024];
std::string ip = "192.168.1.10";
int port = 1234;
struct sockaddr_in client{};
memset(&client, 0, sizeof(client));
client.sin_addr.s_addr = inet_addr(ip.c_str());
client.sin_family = af_inet;
client.sin_port = htons(port);
ret = sendto(sock_fd, buf, sizeof(buf), 0, reinterpret_cast<struct sockaddr *>(&client), sizeof(struct sockaddr));
if(ret < 0){
    perror("udpserver send error!");
}else{
    std::cout << "send success!" << std::endl;
}
        
        usleep(50*1000);
    }
}

8. 编译运行

# 编译
g++ udp_main.cpp -o main -lpthread
# 运行
./main

以上就是linux下使用c/c++进行udp网络编程详解的详细内容,更多关于c++ udp网络编程的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com