linux, petalinux 下的udp 通讯实验

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leon_zeng0/article/details/84332883

udp 是基于tcp/ip协议的无连接通讯。我基于zynq 7000建立了petalinux 系统,希望能有高效有效的通讯方式。以前做了tcp 基于连接的通讯实验,但实际中包会被拆开,感觉有点不好,所以特做了无连接的通讯测试,这就是udp 通讯。

1:实验过程

首先在网上查找了udp 在linux下的c 语言通讯程序。 但我需要运行的环境是zynq 7000上建立的petalinux2018.2 环境。我的环境是在ubuntu16,下安装 petalinux 2018.2实现的。采用交叉编译,petalinux上的udp服务器程序可以运行,可以接收到包,但解析不到地址。这样就不能实现通讯。我也怀疑测试的客户端程序有问题,所以也就写了一个客户端测试程序。

这样还是不行,我就在ubuntu16 下直接cc 这2个程序,发现可以实现通讯。就是在petalinux下运行服务端或客服端就得不到地址。这样在xilinx 论坛上提了此问题,后来终于得到一个提示,修改后就可以各种条件下都可以udp 通讯。

通讯的实验是:客户端程序udpc 发送一个包, 服务端udps得到这个包,显示,并回送一个包,客户端接收到,并显示。这样就验证了通讯。

2:服务端udps.c 的代码

在ubuntu 上运行编译是 :cc udps.c -o udps

在petalinux 上运行,在ubuntu 上运行交叉编译是 :arm-linux-gnueabihf-gcc udps.c -o udps

// Server side implementation of UDP client-server model 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define PORT     8080 
#define MAXLINE 1024 

// Driver code 
int main(int argc,char** argv) {
        int sockfd;
        char buffer[MAXLINE];
        char *hello = "Hello from server";
        struct sockaddr_in servaddr, cliaddr;

        // Creating socket file descriptor 
        if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
                perror("socket creation failed");
                exit(EXIT_FAILURE);
        }

        memset(&servaddr, 0, sizeof(servaddr));
        memset(&cliaddr, 0, sizeof(cliaddr));

        // Filling server information 
        servaddr.sin_family = AF_INET; // IPv4 
        servaddr.sin_addr.s_addr = INADDR_ANY;
        servaddr.sin_port = htons(PORT);

        //int sport;
        if(argc>1)
        {
          int sport;
          sscanf(argv[1],"%d",&sport);
          printf("port is %d\n",sport);
          servaddr.sin_port=htons(sport);

        }

        // Bind the socket with the server address 
        if ( bind(sockfd, (const struct sockaddr *)&servaddr,
                        sizeof(servaddr)) < 0 )
        {
                perror("bind failed");
                exit(EXIT_FAILURE);
        }

        int len, n,cport;
        char addr_buffer[20];
        len=sizeof(struct sockaddr);
        printf("before recvfrom len =%d\n",len);
        n = recvfrom(sockfd, (char *)buffer, MAXLINE,
                                MSG_WAITALL, ( struct sockaddr *) &cliaddr,
                                &len);
        buffer[n] = '\0';
        printf("Client : %s\n", buffer);
        inet_ntop(AF_INET,&(cliaddr.sin_addr.s_addr),addr_buffer,len);
        cport=ntohs(cliaddr.sin_port);
        printf("caddr=%x\n",cliaddr.sin_addr.s_addr);
        printf("addr=%s, len=%d\n",addr_buffer,len);
        printf("c family=%d\n",cliaddr.sin_family);
        printf("c port=%d and=%d\n",cliaddr.sin_port,cport);
        sendto(sockfd, (const char *)hello, strlen(hello),
                MSG_CONFIRM, (const struct sockaddr *) &cliaddr,
                        len);
        printf("Hello message sent.\n");
        //check the server info
        inet_ntop(AF_INET,&(servaddr.sin_addr),addr_buffer,len);
        cport=ntohs(servaddr.sin_port);
        printf("check server addr=%s, port=%d\n",addr_buffer,cport);

        return 0;
}

程序的结构是:

建立socket 文件号,填充服务端信息,缺省端口号是8080,也可以命令行改变,argv[1],

./udps 8000

扫描二维码关注公众号,回复: 5064605 查看本文章

绑定监听端口号,等待客户端,接收信息,显示接收内容,包括客户信息,回送客户信息,关闭文件号,退出。

3: 客户端udpc.c 代码

在ubuntu 上运行编译是 :cc udpc.c -o udpc

在petalinux 上运行,在ubuntu 上运行交叉编译是 :arm-linux-gnueabihf-gcc udpc.c -o udpc

// Client side implementation of UDP client-server model 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define PORT     8080 
#define MAXLINE 1024 

// Driver code 
int main(int argc,char **argv) {
        int sockfd;
        char buffer[MAXLINE];
        char *hello = "Hello from leon client";
        struct sockaddr_in       servaddr;

        // Creating socket file descriptor 
        if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
                perror("socket creation failed");
                exit(EXIT_FAILURE);
        }

        memset(&servaddr, 0, sizeof(servaddr));

        // Filling server information 
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(PORT);
        servaddr.sin_addr.s_addr = INADDR_ANY;

        if(argc>=2)
        {
           inet_pton(AF_INET,argv[1],&(servaddr.sin_addr));
        }
        if(argc>=3){
          int sport;
          sscanf(argv[2],"%d",&sport);
          servaddr.sin_port=htons(sport);
        }
        int n, len;

        sendto(sockfd, (const char *)hello, strlen(hello),
                MSG_CONFIRM, (const struct sockaddr *) &servaddr,
                        sizeof(servaddr));
        printf("Hello message sent.\n");
        char serverbuffer[20];
        int sport;
        n = recvfrom(sockfd, (char *)buffer, MAXLINE,
                                MSG_WAITALL, (struct sockaddr *) &servaddr,
                                &len);
        buffer[n] = '\0';
        printf("Server : %s\n", buffer);
        inet_ntop(AF_INET,&(servaddr.sin_addr.s_addr),serverbuffer,len);
        sport=ntohs(servaddr.sin_port);
        printf("server=%s, port=%d len=%d\n",serverbuffer,sport,len);

        close(sockfd);
        return 0;
}

代码结构是:建立socket 文件号, 填充服务端信息,缺省是本机,端口号为8080。 但可以命令行输入更改,比如:

./udpc 192.168.1.100 8000

发送内容在hello,然后接收,内容在buffer, 显示内容,关闭连接,结束。

4:结果显示

这是在ubuntu16 上的显示

服务端先启动:等待客户来连接,有连接后显示送来的包,解析客户端地址和端口,回送,退出。

liwenz@ubuntu:~/tmp$ ./udps
before recvfrom len =16
Client : Hello from leon client
caddr=100007f
addr=127.0.0.1, len=16
c family=2
c port=52942 and=52942
Hello message sent.
check server addr=0.0.0.0, port=8080
liwenz@ubuntu:~/tmp$ 
 

客户端后启动,发送包后,接收服务端的回送包,然后显示,退出。

liwenz@ubuntu:~/tmp$ ./udpc
Hello message sent.
Server : Hello from server
server=127.0.0.1, port=8080 len=16
liwenz@ubuntu:~/tmp$ 

在petalinux 上的显示也是一样的。但最开始的程序,不能解析客户端的地址。

主要原因是,服务端的recvfrom 中的len 应该先有值。所以服务端开始显示 before recvfrom len=16。

最开始没有赋值,也没有显示校验。 在ubuntu 16 上运行正常,但petalinux 上不能解析地址和端口号。

更改后,就在petalinux 上正常了。
 

猜你喜欢

转载自blog.csdn.net/leon_zeng0/article/details/84332883