网络通信基础之UDP基本通信

UDP特性

UDP(User Datagram Protocol,用户数据报协议) ,是TCP/IP协议族中用于传输层 的协议,特点是无连接、不可靠、乱序(数据乱序了不会重排),不能确保数据不丢失,但数据传输效率高,延迟极低。

UDP服务器端代码实现

cpp 复制代码
//服务器端代码实现
#include <stdio.h>    // printf
#include <iostream>    // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>    //定义socket相关的函数和数据结构
#include <sys/types.h>    //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h>    //调strcat bzero strlen函数
#include <unistd.h>    //调close函数
#define SERVER_PORT 8888    //服务器端口号
#define SERVER_IP "192.168.23.128"    //服务器IP地址

int main(){
    //1.创建用于通信的套接字文件描述符
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);    //SOCK_DGRAM表示基于UDP通信方式
    //参数1:AF_INET表示使用IPv4协议族
    //参数2:SOCK_STREAM表示使用面向连接的TCP协议
    //参数3:协议类型,通常设置为0,表示使用默认协议(参数2指定了协议时参数3填写0即可)
    //返回值:成功返回sfd(socket文件描述符),失败返回-1

    if(sfd == -1){
        perror("socket error");
        return -1;
    }
    printf("socket success sfd = %d\n", sfd);


    //2.绑定IP地址和端口号
    //2.1填充要绑定的ip地址和端口号结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;    //通信域
    sin.sin_port = htons(SERVER_PORT);    //端口号
    sin.sin_addr.s_addr = inet_addr(SERVER_IP);    //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)

    //2.2绑定工作
    //参数1:要被绑定的套接字文件描述符
    //参数2:要绑定的地址信息结构体,需要进行强制类型转换,防止警告
    //参数3:参数2的大小
    //返回值:成功返回0,失败返回-1并置位错误码
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1){
        perror("bind error");
        return -1;
    }
    printf("bind success\n");


    //3.数据收发
    char rbuf[128] = "";
    //定义容器接收对端的地址信息结构体
    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);    //socklen_t表示套接字地址结构体的长度

    while(1){
        //清空容器
        bzero(rbuf, sizeof(rbuf));

        //从客户端中读取信息
        //参数1:套接字文件描述符
        //参数2:存放数据的容器起始地址
        //参数3:读取的数据大小
        //参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
        //参数5:接收对端地址信息结构体的容器
        //参数6:参数5的大小
        //返回值:成功返回读取字节的个数,失败返回-1并置位错误码
        if(recvfrom(sfd, rbuf, sizeof(rbuf), 0, (struct sockaddr*)&cin, &socklen) == -1){
            perror("recvfrom error");
            return -1;
        }
        printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);    //客户端IP地址 客户端端口号 信息
        
        strcat(rbuf, "*_*");    //在消息后加个笑脸

        //将数据发送给客户端
        //参数1:套接字文件描述符
        //参数2:要发送的数据的起始地址
        //参数3:要发送的数据大小
        //参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
        //参数5:要发送的对端 地址信息结构体
        //参数6:参数5的大小
        //返回值:成功返回发送的字节的个数,失败返回-1并置位错误码
        sendto(sfd, rbuf, strlen(rbuf), 0, (struct sockaddr*)&cin, sizeof(cin));
        printf("发送成功\n");
    }


    //4.关闭套接字
    close(sfd);

    return 0;
}

UDP客户端代码实现

cpp 复制代码
//客户端代码实现
#include <stdio.h>    // printf
#include <iostream>    // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>    //定义socket相关的函数和数据结构
#include <sys/types.h>    //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h>    //调strcat bzero strlen函数
#include <unistd.h>    //调close函数
#define SERVER_PORT 8888    //服务器端口号
#define SERVER_IP "192.168.23.128"    //服务器端IP地址
#define CLIENT_PORT 9999    //客户端口号
#define CLIENT_IP "192.168.23.128"    //客户端IP地址

int main(){
    //1.创建用于通信的客户端套接字文件描述符
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);    //客户套接字文件描述符
    if(cfd == -1){
        perror("socket error");
        return -1;
    }
    printf("socket success cfd = %d\n",cfd);


    //2.绑定IP地址和端口号(可选)
    //2.1填充要绑定的ip地址和端口号结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;    //通信域
    cin.sin_port = htons(CLIENT_PORT);    //端口号(使用htons将2字节整数转换为网络字节序)
    cin.sin_addr.s_addr = inet_addr(CLIENT_IP);    //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)
    
    //2.2绑定工作
    if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1){
        perror("bind error");
        return -1;
    }
    printf("bind success\n");


    //3.数据收发
    char wbuf[128] = "";
    //填充服务器的地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SERVER_PORT);
    sin.sin_addr.s_addr = inet_addr(SERVER_IP);

    while(1){
        //清空容器
        bzero(wbuf, sizeof(wbuf));

        //从终端读取用户的数据输入
        fgets(wbuf, sizeof(wbuf), stdin);
        wbuf[strlen(wbuf) - 1] = 0;    //去除fgets读取到的多余换行符\n

        //将数据发送给服务器
        //参数1:套接字文件描述符
        //参数2:要发送的数据的起始地址
        //参数3:要发送的数据大小
        //参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
        //参数5:要发送的对端 地址信息结构体
        //参数6:参数5的大小
        //返回值:成功返回发送的字节的个数,失败返回-1并置位错误码
        sendto(cfd, wbuf, strlen(wbuf), 0, (struct sockaddr*)&sin, sizeof(sin));

        //接收服务器发来的数据(服务器端的地址可以不接收,置为NULL即可)
        //参数1:套接字文件描述符
        //参数2:存放数据的容器起始地址
        //参数3:读取的数据大小
        //参数4:是否阻塞,0表示阻塞,MSG_DONTWAIT表示非阻塞
        //参数5:接收对端地址信息结构体的容器
        //参数6:参数5的大小
        //返回值:成功返回读取字节的个数,失败返回-1并置位错误码
        recvfrom(cfd, wbuf, sizeof(wbuf), 0, NULL, NULL);

        printf("服务器发送的消息为:%s\n", wbuf);
    }


    //4.关闭套接字
    close(cfd);
    
    return 0;
}
相关推荐
lifewange15 小时前
RPC 是什么
网络·网络协议·rpc
档案宝档案管理20 小时前
权限分级管控,全程可追溯,筑牢会计档案安全防线
运维·网络·人工智能
想成为优秀工程师的爸爸20 小时前
第十九篇技术笔记:UDP——相思传得快,飞鸽传书在
笔记·网络协议·tcp/ip·udp·信息与通信
Smart-佀21 小时前
涨薪秘技:智能家居中的BLE协议与实现
网络·arm开发·嵌入式硬件·microsoft
南京码讯光电技术有限公司21 小时前
工业级CPE,4G/5G+WiFi融合,破解严苛环境无线覆盖难题
网络·5g
ai_coder_ai1 天前
在自动化脚本中如何实现网络访问?
网络·autojs·自动化脚本·冰狐智能辅助·easyclick
0xR3lativ1ty1 天前
关闭公网IP的两种方式
网络协议·tcp/ip·php
被摘下的星星1 天前
路由选择协议技术
网络·智能路由器
威联通安全存储1 天前
跨国影视协同:SD-WAN 与边缘快取架构解析
网络
Element_南笙1 天前
VGG网络-深度学习经典架构解析
网络·深度学习·架构