Linux 下的 UDP 编程

2019-10-14

关键字:C 语言的 UDP 编程与实例


 

UDP 连接是一种无连接的网络连接协议。

 

Linux 下的 UDP 编程的函数接口与 TCP 差不了多远。在 UDP 通信模型中,也是以 C/S 模型来通信的。

 

服务端的函数调用流程主要有以下几个:

1、socket()

2、bind()

3、recvfrom() / sendto()

4、close()

 

客户端的函数调用流程主要有以下几个:

1、socket()

2、sendto() / recvfrom()

3、close()

 

 

socket()、bind() 函数:

略,有需要的可以参阅 TCP 编程的文章。

 

sendto() 函数:

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

这个函数与 TCP 编程里的 send() 很像,只不过多了两个参数 dest_addr 与 addrlen 而已。由于 UDP 是无连接式的网络通信,因此很容易猜到这多出来的两个参数和数据接收方的地址有关。

参数 dest_addr 就是一个在填写时要用 sockaddr_in 结构体类型,使用时强转成 sockaddr 结构体类型的参数。用于填写数据接收方的 IP 地址、端口号与通信模式信息。

参数 addrlen 就是结构体 dest_addr 的长度。

 

recvfrom() 函数:

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

这个函数与上面 sendto() 几乎一样。

参数 src_addr 与 addrlen 用于保存数据发送方的网络地址信息。

 

 

实例

 

客户端:

int main(int argc, char *argv[])
{
    int fd = -1;
    int port = 17173;
    
    struct sockadr_in sin;
    
    // 1. 创建 socket fd
    if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(-1);
    }
    
    bzero(&sin, sizeof(sin));
    
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port); // host to net,本地字节序转换成网络字节序。
    
    if(inet_pton(AF_INET, "192.168.77.3", (void *)&sin.sin_addr) != 1)
    {
        perror("inet_pton");
        exit(-1);
    }
    
    char buf[64];
    while(1)
    {
        bzero(buf, 64);
        if(fgets(buf, 64 - 1, stdin) == NULL)
        {
            perror("fgets");
            continue;
        }
        
        sendto(fd, buf, strlen(buf), 0, (struct socketaddr *)&sin, sizeof(sin));
        
        //退出判断。
    }
    
    close(fd);
    
    return 0;
}

 

服务端:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
    int fd = -1;
    struct sockaddr_in sin;
    
    if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(-1);
    }
    
    //允许绑定地址与端口的快速重用。
    int b_reuse = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
    
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    
    if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        perror("bind");
        exit(-1);
    }
    
    char buf[64];
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    while(1)
    {
        bzero(buf, 64);
        if(recvfrom(fd, buf, 64 - 1, 0, (struct sockaddr *)&cin, &addrlen) < 0)
        {
            perror("recvfrom");
            continue;
        }
        
        char ipv4[16];
        if(!inet_ntop(AF_INET, (void *)&cin.sin_addr, ipv4, sizeof(cin)))
        {
            perror("inet_ntop");
            exit(-1);
        }
        
        printf("received from(%s:%d), data:%s\n", ipv4, ntohs(sin.sin_port), buf);
        
    }
    
    return 0;
}

 


 

posted @ 2019-10-14 23:06  大窟窿  阅读(325)  评论(0编辑  收藏  举报