【网络编程】-UDP编程案例

一、什么是UDP?

        1.UDP协议:

        是面向无连接的用户数据报协议,在传输数据前不需要建立连接,且目的主机收到UDP报文后,也不需要给出任何确认。

        2.特点:

                1、相比TCP速度更快

                2、广播和多播应用必须使用UDP

                3、简单的请求和应答应用程序可以使用UDP

        3.C/S架构:

        C/S架构指的是客户端-服务器架构(Client-Server Architecture),它是一种常见的网络通信模型。

  1. 客户端(Client):客户端是发起通信请求的一方。它创建一个UDP套接字(socket),并通过该套接字向服务器发送数据报。客户端通常负责发送请求、接收响应以及处理服务器返回的数据。
  2. 服务器(Server):服务器是接收并处理客户端请求的一方。它创建一个UDP套接字,并在指定的端口上监听客户端的请求。当服务器接收到客户端发送的数据报时,会根据请求进行相应的处理,并将处理结果发送回客户端
 疑问:client 能否接收数据?server 能否发送数据呢?

            其实在网络编程开发中 client 和 server 双方既可以有发送数据还可以接收数据;一般认为提供服务的一方为 server;而接受服务的另一方为 clien。

注意点:

        ①服务器之所以要bind,因为本地端口port需要固定,不是随机;

        ② 服务器也可以给客服端发送数据;

        ③客户端也可以bind,但一般不这样。

二、案例

使用UDP,实现简单的QQ功能,要求:能够指定发给某个IP。

1.发送函数

void *send_deal(void *arg)
{
    //从参数中获取套接字描述符
    int sockfd = *(int *)arg;
    //定义目的地址结构体
    struct sockaddr_in dst_addr;
    //清零地址结构
    bzero(&dst_addr,sizeof(dst_addr));
    //设置地址族为IPV4
    dst_addr.sin_family = AF_INET;
    while(1)
    {
        char buf[128] = "";
        //读取用户数据
        fgets(buf,sizeof(buf),stdin);
        //去掉末尾换行符
        buf[strlen(buf)-1]=0;

        //如果用户改变目的地址
        if(strncmp(buf,"sayto",5)==0)
        {
            unsigned short port = 0;
            char ip[16] = "";
            //从字符串中解析IP地址
            sscanf(buf,"sayto %s %hu",ip,&port);
            //设置端口
            dst_addr.sin_port = htons(port);
            //设置IP地址
            inet_pton(AF_INET,ip,&dst_addr.sin_addr.s_addr);
            continue;
        }
        //发送数据
        sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&dst_addr,sizeof(dst_addr));

        //用户输入q,退出循环
        if(strcmp(buf,"q")==0)
        {
            break;            
        }
    }
    return NULL;

}

2.接收函数

//接受函数
void *recv_deal(void *arg)
{
    //从参数中获取套接字描述符
    int sockfd = *(int *)arg;

    while (1)
    {
        //客户端结构体
        struct sockaddr_in cli_addr;
        //结构体的长度
        socklen_t cli_len = sizeof(cli_addr);

        unsigned short port = 0;//存储端口数量
        char ip[16] = "";//存储IP
        unsigned char buf[512]= "";//接收的数据
        int len = 0;//接收的长度

        //接收数据
        len = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&cli_addr,&cli_len);

        if(len>=0)//接收成功
        {
            port = ntohs(cli_addr.sin_port);//得到端口号
            inet_ntop(AF_INET,&cli_addr.sin_addr.s_addr,ip,16);

            printf("%s:%hu %s\n",ip,port,buf);
        }
    }
    return NULL;
}

3.主函数

//检查命令行参数数量
    if(argc!=2)
    {
        printf("./a.out 8000\n");
        return 0;
    }
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    //检查套接字是否创建成功
    if(sockfd<0)
    {
        perror("sockfd");
        return 0;
    }
    //定义服务器地址结构体并初始化为0
    struct sockaddr_in my_addr;
    bzero(&my_addr,sizeof(my_addr));
    //设置地址族为IPV4
    my_addr.sin_family = AF_INET;
    //设置端口号,使用命令行参数,并转换为网络字节序
    my_addr.sin_port = htons(atoi(argv[1]));
    //绑定到所有的网络接口
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //绑定地址到套接字
    int ret = bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
    //检查是否绑定成功
    if(ret<0)
    {
        perror("bind");
        close(sockfd);//关闭套接字
        return 0;
    }
    //创建发送线程
    pthread_t send_tid;
    pthread_create(&send_tid,NULL,send_deal,(void *)&sockfd);
    //创建接收线程
    pthread_t recv_tid;
    pthread_create(&recv_tid,NULL,recv_deal,(void *)&sockfd);
    //主线程等待发送线程结束
    pthread_join(send_tid,NULL);
    //取消接收线程
    pthread_cancel(recv_tid);
    //主线程等待接收线程结束
    pthread_join(recv_tid,NULL);
    //关闭套接字
    close(sockfd);
    return 0;

主要用到头文件:

// 导入标准输入输出库
#include <stdio.h>
// 导入套接字相关库
#include <sys/socket.h>
// 导入UNIX标准库,包含了close函数
#include <unistd.h>
// 导入网络地址库,包括sockaddr_in结构体
#include <netinet/in.h>
// 导入字符串处理函数,例如bzero
#include <string.h>
// 导入IP地址处理函数,例如inet_pton
#include <arpa/inet.h>
// 导入线程库
#include <pthread.h>
// 导入标准库,包含了atoi函数
#include <stdlib.h>

可以使用网络调试助手,运行就能实现啦。

注:

        编译时如没有线程相应的库,线程函数的程序在 pthread 库中,故链接时要加上参数-lpthread。

        改变IP和端口号:sayto 具体IP和端口号port;

        结束:输入q。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值