Linux网络编程|UDP编程

举报
白茶加冰 发表于 2023/09/15 23:35:16 2023/09/15
【摘要】 ​ ​编辑 一.UDP概念及特点UDP:用户数据包协议UDP用户数据报协议: 无连接,不可靠的协议,UDP不需要连接,所以进行高效率传输适用情况: 在接收到数据.给出应答较为困难的网络 用于广播/组播 QQ/微信 视频通话/语音电话流媒体,VoIP,IPTV等网络服务 二.UDP编程流程通信流程   --- 无连接(connect accept)的过程 UDP 无法判断客户端是否退出: 使用...

 编辑

 一.UDP概念及特点


UDP:用户数据包协议

UDP用户数据报协议: 无连接,不可靠的协议,UDP不需要连接,所以进行高效率传输

适用情况: 

  1. 在接收到数据.给出应答较为困难的网络
  2.  用于广播/组播 
  3. QQ/微信 视频通话/语音电话
  4. 流媒体,VoIP,IPTV等网络服务

 二.UDP编程流程

通信流程   --- 无连接(connect accept)的过程 

UDP 无法判断客户端是否退出: 使用心跳包, 使用客户端, 定时给服务器发送内容

编辑


UDP流程:(类似发短信)

server:

创建数据报套接字(socket(,SOCK_DGRAM,))----->有手机

绑定网络信息(bind())-----------> 绑定IP和port(发短信知道发给谁)

接收信息(recvfrom())------------>接收信息,同时可以获取到发送者的IP和port

关闭套接字(close())-------------->接收完毕


client:

创建数据报套接字(socket())----------------------->有手机

指定服务器的网络信息------------------------------>有对方号码

发送信息(sendto())---------------------------->发送短信,根据填充的结构体信息

关闭套接字(close())--------------------------->发送完

注意:

1、对于TCP是先运行服务器,客户端才能运行。

2、对于UDP来说,服务器和客户端运行顺序没有先后,因为是无连接,所以服务器和客户端谁先开始,没有关系,

3、UDP一个服务器可以同时连接多个客户端。想知道是哪个客户端登录,可以在服务器代码里面打印IP和端口号。

以下内容面试可能会问: 感兴趣可以自己测试一下

4、UDP,客户端当使用send的时候,上面需要加connect,,这个connect不是代表连接的作用,而是指定客户端即将要发送给谁数据。这样就不需要使用sendto而用send就可以。

5、在TCP里面,也可以使用recvfrom和sendto,使用的时候将后面的两个参数都写为NULL就OK。


三.函数接口 

 (1)socket 创建套接字

int socket(int domain, int type, int protocol);

头文件: #include <sys/types.h>

               #include <sys/socket.h>

domain:协议族

                AF_UNIX, AF_LOCAL          本地通信

                AF_INET                               ipv4

                AF_INET6                             ipv6

type:套接字类型

                SOCK_STREAM:                流式套接字

                SOCK_DGRAM:               数据报套接字

protocol:协议 - 填0 自动匹配底层 ,根据type系统默认自动帮助匹配对应协议


       传输层:IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP

       网络层:htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)

成功:socket文件描述符

失败:-1,设置错误码

(2)bind 绑定套接字

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

头文件:#include<sys/types.h>

            #include<sys/socket.h>

            #include<netinet/in.h>

            #include<netinet/ip.h>

sockfd:套接字文件描述符

addr:通信结构体(提供的是通用结构体,需要根据选择通信方式,填充对应 结构体-通信当             时socket第一个参数确定,需要强转)


通用结构体:

struct sockaddr {

        sa_family_t  sa_family;

        char        sa_data[14];

}

ipv4通信结构体:

struct sockaddr_in {

        sa_family_t    sin_family; ----协议族

         in_port_t      sin_port; ----端口

        struct in_addr sin_addr; ----ip结构体

};

struct in_addr {

         uint32_t       s_addr; --ip地址

};


addrlen:结构体大小

(3)recvfrom  接收数据

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

                                                                       struct sockaddr *src_addr, socklen_t *addrlen);

sockfd:套接字描述符

buf:接收缓存区的首地址

len:接收缓存区的大小

flags:0  接收数据 并 阻塞

           MSG_DONTWAIT: 设置非阻塞


src_addr: 发送端的网络信息结构体的指针(对方的 caddr)

addrlen:发送端的网络信息结构体的大小的指针(对方的 caddr)

返回值:

成功:接收的字节个数,接收到的数据为0 : 0

失败:-1

(4)sendto 发送数据

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

                                                                           const struct sockaddr *dest_addr, socklen_t 

sockfd:套接字描述符

buf:发送缓存区的首地址

len:发送缓存区的大小

flags:0  发送消息并阻塞

src_addr:接收端的网络信息结构体的指针

addrlen:接收端的网络信息结构体的大小

返回值: 

        成功:发送的字节个数

        失败:-1

四.综合代码 

(1)server:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("sockfd err");
        return -1;
    }

    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int len = sizeof(caddr);

    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind is err");
        exit(0);
    }
    printf("bind ok\n");
    printf("等待接收客户端内容\n");
    while (1)
    {
        int recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
        if (recvbyte < 0)
        {
            perror("bind is err");
            exit(0);
        }
        else
        {
            printf("ip:%s  port:%d  内容:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);
        }
    }
    close(sockfd);
    return 0;
}


(2)client:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("sockfd err");
        return -1;
    }

    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[2]));
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    int len = sizeof(saddr);
    while (1)
    {
        fgets(buf, sizeof(buf), stdin);
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = '\0';
        sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, len);
    }
    close(sockfd);
    return 0;
}

编辑


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。