网络通信基础之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;
}
相关推荐
发光小北6 小时前
四路can转WIFI在现场应用中有什么问题?
网络协议
不像程序员的程序媛6 小时前
检测网络的命令mtr详解
网络
天启HTTP7 小时前
爬虫防封核心原理:IP轮换机制与风控规避逻辑
linux·服务器·网络·爬虫·tcp/ip
运维行者_7 小时前
网络性能监控怎么做?从自动发现到根因分析的4个环节
运维·服务器·网络·人工智能·支持向量机
hz567899 小时前
涉密视频会议设备配置指南:终端、音视频采集与配套设施选型
服务器·网络·数据库·安全·实时音视频·信息与通信·智能硬件
优橙教育9 小时前
零基础学AI应用开发要多久?3个月能到什么水平
服务器·开发语言·网络·php
AIgorithmGEEK10 小时前
[Linux]从手写报头到内核套路:序列化、反序列化与自定义协议全链路
linux·运维·服务器·网络·序列化·反序列化
深圳恒讯13 小时前
海外服务器延迟高怎么解决?从线路到TCP协议的6层排查清单
运维·服务器·tcp/ip
物联网软硬件开发-轨物科技14 小时前
【轨物洞见】什么是产品碳足迹(PCF)?ISO 14067 计算方法与应用场景深度解读
大数据·网络·人工智能