linux下C++实现UDP通信

简要介绍UDP原理,通过代码实例讲解。
这里写图片描述
本篇博客不强调server跟client 的概念,重在实现双方互通。
收的一方: socket()->bind()->recvfrom()->close()
发的一方:socket()->sendto()->close()
只有收数据的一方需要bind(),而发送的一方不需要bind()。由上图可以看出,bind()的一方只有收到消息(recvfrom)后才能给另一方发送消息。
同一台电脑如果要实现互发消息,则无法同时bind()同一个端口号,两方需要bind()不同的端口号才能实现自由互发,否则bind()的一方将会出现阻塞等待消息的现象。
下面代码中介绍UDP的C++实现。

1.设置两个端口实现互发数据
接受一方:

#include<sys/select.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>

int main(){

    //同一台电脑测试,需要两个端口
    int port_in  = 12321;
    int port_out = 12322;
    int sockfd;

    // 创建socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1==sockfd){
        return false;
        puts("Failed to create socket");
    }

    // 设置地址与端口
    struct sockaddr_in addr;
    socklen_t          addr_len=sizeof(addr);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;       // Use IPV4
    addr.sin_port   = htons(port_out);    //
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // Time out
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 200000;  // 200 ms
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    // Bind 端口,用来接受之前设定的地址与端口发来的信息,作为接受一方必须bind端口,并且端口号与发送方一致
    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){
        printf("Failed to bind socket on port %d\n", port_out);
        close(sockfd);
        return false;
    }

    char buffer[128];
    memset(buffer, 0, 128);

    int counter = 0;
    while(1){
        struct sockaddr_in src;
        socklen_t src_len = sizeof(src);
        memset(&src, 0, sizeof(src));

        int sz = recvfrom(sockfd, buffer, 128, 0, (sockaddr*)&src, &src_len);
        if (sz > 0){
            buffer[sz] = 0;
            printf("Get Message %d: %s\n", counter++, buffer);
        }
        else{
            puts("timeout");
        }
    }

    close(sockfd);
    return 0;
}

发送一方:

#include<sys/select.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>

int main(){
    int port_in  = 12321;
    int port_out = 12322;
    int sockfd;

    // 创建socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1==sockfd){
        return false;
        puts("Failed to create socket");
    }

    // 设置地址与端口
    struct sockaddr_in addr;
    socklen_t          addr_len=sizeof(addr);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;       // Use IPV4
    addr.sin_port   = htons(port_in);    //
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // Time out
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 200000;  // 200 ms
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    // 绑定获取数据的端口,作为发送方,不绑定也行
    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){
        printf("Failed to bind socket on port %d\n", port_in);
        close(sockfd);
        return false;
    }

    int counter = 0;
    while(1){


        addr.sin_family = AF_INET;
        addr.sin_port   = htons(port_out);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);

        sendto(sockfd, "hello world", 11, 0, (sockaddr*)&addr, addr_len);
        printf("Sended %d\n", ++counter);
        sleep(1);
    }

    close(sockfd);
    return 0;
}

2.设置一个端口号实现互发数据
server方必须收到一次client方的数据后,才能实现随意互发数据。
使用方法为:运行server->运行client->键盘在client输入->随意互发数据。
server:

//只有在server接收到消息后才能实现互发数据
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888//唯一端口号
int main(){
    int ser_sockfd;
    int len;
    fd_set rfds;
    socklen_t addrlen;
    char seraddr[100];
    struct sockaddr_in ser_addr;
    int retval, maxfd;
    //建立socket
    ser_sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(ser_sockfd<0){
        printf("I cannot socket success\n");
        return 1;
     }
    //设置地址与端口
    addrlen=sizeof(struct sockaddr_in);
    bzero(&ser_addr,addrlen);
    ser_addr.sin_family=AF_INET;
    ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    ser_addr.sin_port= htons (SERVER_PORT);
    //server绑定,才能接受client的数据
    if(bind(ser_sockfd,(struct sockaddr *)&ser_addr,addrlen)<0){
        printf("connect");
        return 1;
    }
    while(1){
        bzero(seraddr,sizeof(seraddr));
        len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen);
        /*显示client端的网络地址*/
        printf("receive from %s\n",inet_ntoa(ser_addr.sin_addr));
        /*显示客户端发来的字串*/
        printf("recevce:%s",seraddr);
        /*输入字串返回给client端*/
        while(1)
        {
             /*把可读文件描述符的集合清空*/
             FD_ZERO(&rfds);
             /*把标准输入的文件描述符加入到集合中*/
             FD_SET(0, &rfds);
             maxfd = 0;
             /*把当前连接的文件描述符加入到集合中*/
             FD_SET(ser_sockfd, &rfds);
             /*找出文件描述符集合中最大的文件描述符*/
             if(maxfd < ser_sockfd)
                maxfd = ser_sockfd;
             retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
             if(FD_ISSET(ser_sockfd,&rfds))//client发消息来会出发进入
             {
             len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen);                   printf("recevce:%s",seraddr);
              }
                 if(FD_ISSET(0, &rfds))//键盘输入会触发进入
                 {
                     len=read(STDIN_FILENO,seraddr,sizeof(seraddr));
                     sendto(ser_sockfd,seraddr,len,0,(struct sockaddr*)&ser_addr,addrlen);
                 }
        }
    }
    return 0;
}

client:

#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888   //唯一端口
int main(int argc,char **argv){
    int cli_sockfd;
    int len;
    fd_set rfds;
    socklen_t addrlen;
    struct sockaddr_in cli_addr;
    char buffer[256];
    char buffer1[256];
    int retval, maxfd;
    //创建socket
    cli_sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(cli_sockfd<0){
        printf("I cannot socket success\n");
        return 1;
    }
    //配置地址与端口
    addrlen=sizeof(struct sockaddr_in);
    bzero(&cli_addr,addrlen);
    cli_addr.sin_family=AF_INET;
    cli_addr.sin_addr.s_addr=htonl(INADDR_ANY);//任何主机地址
    cli_addr.sin_port=htons(SERVER_PORT);
//这里作为发送方,不需要绑定bind()
    while(1)
    {
        bzero(buffer,sizeof(buffer));
        /* 从标准输入设备取得字符串*/   len=read(STDIN_FILENO,buffer,sizeof(buffer));
        /* 将字符串传送给server端*/
        sendto(cli_sockfd,buffer,len,0,(struct sockaddr*)&cli_addr,addrlen);
        /* 接收server端返回的字符串*/
        while(1)
        {
                     /*把可读文件描述符的集合清空*/
                     FD_ZERO(&rfds);
                     /*把标准输入的文件描述符加入到集合中*/
                     FD_SET(0, &rfds);
                     maxfd = 0;
                     /*把当前连接的文件描述符加入到集合中*/
                     FD_SET(cli_sockfd, &rfds);
                     /*找出文件描述符集合中最大的文件描述符*/
                     if(maxfd < cli_sockfd)
                         maxfd = cli_sockfd;

                     retval = select(maxfd+1, &rfds, NULL, NULL, NULL);

                    if(FD_ISSET(cli_sockfd,&rfds))//server发来数据将会触发进入循环
                    {

                        len=recvfrom(cli_sockfd,buffer1,sizeof(buffer1),0,(struct sockaddr*)&cli_addr,&addrlen);
                        printf("receive: %s",buffer1);
                    }
                     if(FD_ISSET(0, &rfds))//键盘输入会触发进入
                     {
                         len=read(STDIN_FILENO,buffer,sizeof(buffer));
                         sendto(cli_sockfd,buffer,len,0,(struct sockaddr*)&cli_addr,addrlen);
                     }

        }
    }
    close(cli_sockfd);
    return 0;
}

补充:inet_addr(“127.0.0.1”)将一个点分十进制的IP转换成一个长整数型数(u_long类型)。

WALDM

  • 11
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Linux双网卡指的是在一台Linux服务器上同时使用两个网卡进行网络连接。通过配置双网卡,可以实现网络负载均衡、网络冗余和网络隔离等功能。 在Linux系统中,可以使用ifconfig命令查看和设置网卡信息。首先,通过ifconfig命令查看当前系统中存在的网卡接口,然后通过配置文件修改网络接口的配置信息,使得两个网卡同时工作。 在C程序中,可以使用socket函数创建UDP套接字,然后使用bind函数将套接字绑定到一个特定的本地IP地址和端口号上。接着,使用recvfrom函数从UDP套接字中接收数据报文,并使用sendto函数将数据报文发送到指定的目标IP地址和端口号。 在实际应用中,可以使用两个UDP套接字分别监听两个网卡的IP地址和端口号,以实现双网卡的功能。通过套接字的接收和发送函数,可以在不同的网卡上接收和发送数据报文。 另外,还可以通过设置套接字的选项,如SO_REUSEADDR和SO_BINDTODEVICE等,来实现更精细的控制。 综上所述,Linux双网卡和C语言的socket编程可以结合使用,通过配置双网卡实现网络负载均衡和网络隔离等功能,并使用UDP套接字进行数据的接收和发送。 ### 回答2: Linux双网卡C语言Socket UDP是指在Linux系统下,基于C语言编程,使用Socket和UDP协议进行网络通信的双网卡配置。 网卡是计算机连接网络的一种硬件设备,有时我们需要使用多个网卡来实现更高效的网络通信。在Linux系统中,我们可以通过配置双网卡来实现此目的。 使用C语言编程,我们可以使用Socket库函数来进行网络通信。Socket是一种能够在不同计算机之间进行通信的API接口,可以用于UDP、TCP等网络协议。 UDP是用户数据报协议,它是一种无连接的、不可靠的传输协议,适用于一对一或多对一的通信UDP在传输数据时效率高,但无法保证数据的可靠性和顺序性。 在双网卡配置中,我们可以使用C语言编写程序,通过Socket和UDP协议进行通信。首先,我们需要调用Socket函数创建一个套接字,并使用bind函数将套接字绑定到一个特定的IP地址和端口号上。然后,我们可以使用recvfrom函数接收来自其他计算机的数据,并使用sendto函数将数据发送给其他计算机。 通过配置两个不同的网卡,我们可以利用双网卡进行双向通信。例如,我们可以将一个网卡连接到局域网,另一个网卡连接到互联网,这样就可以实现局域网和互联网之间的数据传输。 总之,Linux双网卡C语言Socket UDP是指在Linux系统下,利用C语言编程,通过Socket库函数和UDP协议进行双网卡配置和网络通信的技术。这种技术可以实现高效的双向数据传输,并适用于一对一或多对一的通信场景。 ### 回答3: Linux 双网卡 c socket UDP 是指在 Linux 操作系统中,使用 C 编程语言编写的程序,通过 Socket 编程接口,使用 UDP 协议进行网络通信。 双网卡是指计算机系统中同时安装了两块或多块网卡,通过这些网卡可以连接到不同的网络。在使用双网卡的情况下,我们可以在程序中指定使用哪一块网卡进行数据传输,实现数据的接收和发送。在使用双网卡的环境下,程序可以同时监听多个网络上的数据包,并且可以选择性地进行数据的处理。 Socket 是一种网络编程的接口,是一种软件接口,用于支持进程间的网络通信。在 C 语言中,我们使用 Socket 编程接口来创建网络连接,发送和接收数据。通过 Socket 编程接口,我们可以轻松地实现各种网络通信方式,包括 TCP、UDP 以及其他协议。 UDP 是用户数据报协议(User Datagram Protocol)的缩写,它是一种无连接的、不可靠的传输协议。与 TCP 不同,UDP 不需要在传输之前建立连接,直接将数据通过 UDP 数据包发送给目标主机。由于 UDP 无连接且不可靠,所以它的传输速度比 TCP 快,但是在传输过程中可能会出现数据丢失或者乱序的问题。在使用 UDP 进行网络通信时,我们需要使用程序来处理这些问题,确保数据的可靠性。 总结来说,Linux 双网卡 C Socket UDP 是指在 Linux 操作系统中,通过 C 编程语言编写的程序,使用 Socket 编程接口,利用 UDP 协议进行网络通信。在双网卡环境下,程序可以指定使用哪一块网卡进行数据传输,并且可以实现数据的接收和发送。同时,程序也需要处理 UDP 协议带来的数据丢失或者乱序等问题,确保数据的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值