网络通信基础之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;
}
相关推荐
Yang96113 分钟前
鼎讯信通热剥钳实测:大芯径光纤如何做到无损剥除
网络
贞明电子8 小时前
工业三色报警灯怎么接入项目系统?开关量与RS485控制应用指南
运维·网络·微信公众平台·贞明电子
明天也要努力学习9 小时前
HTTP 协议的基本格式和 fiddler 的用法
网络协议·http·fiddler
HideF9 小时前
Linux
linux·服务器·网络
万联WANFLOW9 小时前
海外网络故障怎么排查?Cloudflare 三季度断网报告解读与 mtr 实战
运维·网络·故障分析
听风说ml9 小时前
socket编程 【C语言】
c语言·udp·tcp·socket编程
sbjdhjd9 小时前
网工进阶笔记:H3CSE 园区网全栈技术与协议汇总
网络·笔记·云计算·ssh·网络工程·vlan·aaa
taktok_ai11 小时前
用 cc-switch 连接 Taktok
网络
小嘉丶学长13 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节
LCG米14 小时前
STM32驱动W5500以太网模块实测:TCP吞吐瓶颈定位、TX指针回绕陷阱与断线重连保活落地
stm32·单片机·嵌入式硬件·tcp/ip