网络通信基础之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;
}
相关推荐
数据知道2 小时前
claw-code 源码分析:从 REPL 到服务端——CLI / HTTP(SSE) / LSP 多入口如何共享同一颗 runtime 心?
python·网络协议·http·ai·里氏替换原则·claude code
酿情师2 小时前
2026软件系统安全赛初赛RSA(赛后复盘)
android·网络·安全·密码学·rsa
路溪非溪2 小时前
Linux中Netlink简介和使用总结
linux·网络·arm开发·驱动开发
Mr_Xuhhh2 小时前
[特殊字符] 《网络知识和Servlet重点知识整理》
网络·servlet
952362 小时前
网络原理 - HTTP / HTTPS
网络·http·https
sichuanwww2 小时前
套接字Socket编程样例
udp·socket·tcp
克莱因3582 小时前
思科 单区域OSPF(1
网络·路由·思科
Oll Correct2 小时前
实验十四:IPv4地址的无分类编址方法
网络·笔记
23zhgjx-ctl2 小时前
111111
网络·智能路由器