Linux编程(通信协议---udp)

UDP(用户数据报协议)是一种无连接的网络协议,主要用于快速传输数据。以下是UDP协议的一些主要特点:

  1. **无连接**:UDP是无连接的协议,这意味着在数据传输之前不需要建立连接。每个UDP数据包都是独立的,不需要前一个数据包的确认。

  2. **简单性**:UDP的协议结构相对简单,只有8字节的UDP头部,包括源端口、目的端口、长度和校验和。

  3. **快速性**:由于UDP不需要建立连接和进行数据确认,因此它的数据传输速度通常比TCP快。

  4. **不保证可靠性**:UDP不保证数据的可靠传输,也就是说,数据包可能会丢失、重复或乱序到达。

  5. **无拥塞控制**:UDP没有拥塞控制机制,这意味着它不会根据网络的拥堵情况调整数据传输速率。

  6. **支持多播和广播**:UDP支持多播和广播数据传输,这使得它可以用于发送数据到多个接收者。

  7. **校验和**:UDP包含一个校验和字段,用于检测数据在传输过程中是否出现错误。如果检测到错误,接收方可以选择丢弃该数据包。

  8. **应用场景**:UDP通常用于那些对实时性要求高但可以容忍一定数据丢失的应用,如视频会议、在线游戏、DNS查询等。

  9. **端口号**:UDP使用端口号来区分不同的服务或进程,每个UDP数据包都包含源端口和目的端口。

  10. **数据报长度**:UDP数据报的长度可以是任意的,但最大长度受限于IP数据报的最大长度,通常是65507字节。

2、框架: C/S模式

服务器端 server:socket() ===>bind()===>recvfrom()===>close()

客户端 client:socket() ===>bind()===>sendto() ===>close()

注意:socket()的参数需要调整。

socket(PF_INET,SOCK_DGRAM,0);

bind() 客户端是可选的,服务器端是必须选的。

1、int socket(int domain, int type, int protocol);

功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain 地址族,PF_INET == AF_INET ==>互联网程序

PF_UNIX == AF_UNIX ==>单机程序

type 套接字类型:

SOCK_STREAM 流式套接字 ===》TCP

SOCK_DGRAM 用户数据报套接字===>UDP

SOCK_RAW 原始套接字 ===》IP

protocol 协议 ==》0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id

失败 -1;

2、int bind(int sockfd, struct sockaddr *my_addr,

socklen_t addrlen);

功能:如果该函数在服务器端调用,则表示将参数1相关

的文件描述符文件与参数2 指定的接口地址关联,

用于从该接口接受数据。

如果该函数在客户端调用,则表示要将数据从

参数1所在的描述符中取出并从参数2所在的接口

设备上发送出去。

注意:如果是客户端,则该函数可以省略,由默认

接口发送数据。

参数:sockfd 之前通过socket函数创建的文件描述符,套接字id

my_addr 是物理接口的结构体指针。表示该接口的信息。

struct sockaddr 通用地址结构

{

u_short sa_family; 地址族

char sa_data[14]; 地址信息

};

转换成网络地址结构如下:

struct _sockaddr_in ///网络地址结构

{

u_short sin_family; 地址族

u_short sin_port; ///地址端口

struct in_addr sin_addr; ///地址IP

char sin_zero[8]; 占位

};

struct in_addr

{

in_addr_t s_addr;

}

socklen_t addrlen: 参数2 的长度。

返回值:成功 0

失败 -1;

发送接收函数:

3、ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

const struct sockaddr *dest_addr, socklen_t addrlen);

功能:用于UDP协议中向对方发送数据。

参数:sockfd 本地的套接字id

buff 本地的数据存储,一般是要发送的数据。

len 要发送的数据长度

flags 要发送数据方式,0 表示阻塞发送。

dest_addr: 必选,表示要发送到的目标主机信息结构体。

addrlen :目标地址长度。

返回值:成功 发送的数据长度

失败 -1;

4、ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

功能:用于UDP协议中获取对方发送的数据。

参数:sockfd 本地的套接字id

buff 要存储数据的内存区,一般是数组或者动态内存。

len 要获取的数据长度,一般是buff的大小。

flags 获取方式,0 阻塞

src_addr 可选,表示对方的地址信息结构体,

如果为NULL,表示不关心对方地址。

addrlen 对方地址信息结构体大小。

如果对方地址是NULL,则该值也为NULL。

返回值:成功 接收到的数据长度

失败 -1;

《1》实现udp通信示例代码:

服务器端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    // man 7 ip 
    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("192.168.203.128");
    int ret = bind(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    socklen_t len = sizeof(cli);
    while(1)
    {
        char buf[512]={0};
        recvfrom(sockfd,buf,sizeof(buf),0,(SA)&cli,&len);
        time_t tm;
        time(&tm);
        sprintf(buf,"%s %s",buf,ctime(&tm));
        sendto(sockfd,buf,strlen(buf),0,(SA)&cli,len);
    }
    close(sockfd);
    return 0;
}

客户端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);


int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("192.168.203.128");

    while(1)
    {
        char buf[512]="hello,this is udp test";
        sendto(sockfd,buf,strlen(buf),0,(SA)&ser,sizeof(ser));
        bzero(buf,sizeof(buf));
        recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
        printf("buf is %s\n",buf);
        sleep(1);
    }
    close(sockfd);
    return 0;
}

《2》udp实现文件传输

服务器端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr * (SA);
int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    // man 7 ip 
    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    //ser.sin_addr.s_addr = inet_addr("127.0.0.1");
    ser.sin_addr.s_addr = INADDR_ANY;
    int ret = bind(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    socklen_t len = sizeof(cli);
    int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);
    if(-1 == fd)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        char buf[512]={0};
        int rd_ret = recvfrom(sockfd,buf,sizeof(buf),0,(SA)&cli,&len);
        if(0 == strcmp(buf,"^_^"))
        {
            break;
        }
        write(fd,buf,rd_ret);
        bzero(buf,sizeof(buf));
        strcpy(buf,"go on");
        sendto(sockfd,buf,strlen(buf),0,(SA)&cli,len);
    }
    close(sockfd);
    close(fd);
    return 0;
}

客户端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr * (SA);

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }
    struct sockaddr_in ser;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("192.168.203.128");
    int fd = open("/home/linux/1.png",O_RDONLY);
    if(-1 == fd)
    {
        perror("open");
        exit(1);
    }
    char buf[512]={0};
    while(1)
    {
        bzero(buf,sizeof(buf));
        int rd_ret = read(fd,buf,sizeof(buf));
        if(0==rd_ret)
        {
            break;
        }
        sendto(sockfd,buf,rd_ret,0,(SA)&ser,sizeof(ser));
        bzero(buf,sizeof(buf));
        recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
    }
    
    bzero(buf,sizeof(buf));
    strcpy(buf,"^_^");
    sendto(sockfd,buf,3,0,(SA)&ser,sizeof(ser));
    close(sockfd);
    close(fd);
    return 0;
}

《3》udp实现小聊天室功能

服务器端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {CMD_LOGIN,CMD_CHAT,CMD_LOGOUT}TYPE;
typedef struct 
{
    TYPE type;
    char name[50];
    char context[128];

}MSG;
typedef struct 
{
    struct sockaddr_in cli;
    int flag; // 0  free 1 occu
}LIST;
#define MAX 10
LIST list[MAX]={0};
int do_login(int sockfd,MSG* msg,struct sockaddr_in* cli)
{
    int i = 0 ;
    for(i=0;i<MAX;i++)
    {
        if(1 == list[i].flag )
        {
            sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
        }
    }
    for(i=0;i<MAX;i++)
    {
        if(0 == list[i].flag )
        {
            list[i].flag =1;
            //list[i].cli = *cli;
            memcpy(&list[i].cli,cli,sizeof(*cli));
            break;
        }
    }
    return 0;
}

int do_chat(int sockfd, MSG* msg,struct sockaddr_in*cli)
{
     int i = 0 ;
    for(i=0;i<MAX;i++)
    {
        if(1 == list[i].flag && 0!=memcmp(&list[i].cli,cli,sizeof(*cli)) )
        {
            sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));
        }
    }
}
int do_logout(int sockfd, MSG* msg,struct sockaddr_in*cli)
{
    return 0;
}
int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    // man 7 ip 
    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    bzero(&cli,sizeof(cli));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");
    int ret = bind(sockfd,(SA)&ser,sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        exit(1);
    }
    socklen_t len = sizeof(cli);
    MSG msg;
    while(1)
    {
        bzero(&msg,sizeof(msg));
        recvfrom(sockfd,&msg,sizeof(msg),0,(SA)&cli,&len);
        switch(msg.type)
        {
            case CMD_LOGIN:
                do_login(sockfd,&msg,&cli);
                break;
            case CMD_LOGOUT:
                do_logout(sockfd,&msg,&cli);
                break;
            case CMD_CHAT:
                do_chat(sockfd,&msg,&cli);
                break;
        
        }
    }
    close(sockfd);
    return 0;
}

客户端:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {CMD_LOGIN,CMD_CHAT,CMD_LOGOUT}TYPE;
typedef struct 
{
    TYPE type;
    char name[50];
    char context[128];

}MSG;
int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    // man 7 ip 
    struct sockaddr_in ser,cli;
    bzero(&ser,sizeof(ser));
    ser.sin_family = AF_INET;
    // 大小端转化 host to net short 
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");
    socklen_t len = sizeof(cli);
    MSG msg;
    char name[50]={0};
    printf("input name:");
    fgets(name,sizeof(name),stdin);
    name[strlen(name)-1]='\0';

    msg.type = CMD_LOGIN;
    strcpy(msg.name ,name);
    strcpy(msg.context,"login");

    sendto(sockfd,&msg,sizeof(msg),0,(SA)&ser,sizeof(ser));

    pid_t pid = fork();
    if(pid>0)
    {
        while(1)
        {
            bzero(&msg,sizeof(msg));
            recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);    
            printf("%s:%s\n",msg.name,msg.context);
        }
    }
    else if(0==pid)
    {
        while(1)
        {
            printf("to all");    
            char buf[128]={0};
            strcpy(msg.name,name);
            msg.type = CMD_CHAT;
            fgets(msg.context,sizeof(msg.context),stdin);//#quit
            msg.context[strlen(msg.context)-1]='\0';
            if(0==strcmp(msg.context,"#quit"))
            {
                msg.type = CMD_LOGOUT;
                strcpy(msg.context,"CMD_LOGOUT");
            }
            sendto(sockfd,&msg,sizeof(msg),0,(SA)&ser,sizeof(ser));
        }
    }
    else 
    {
        perror("fork");
        exit(1);
    }
    close(sockfd);
    return 0;
}
相关推荐
dsywws几秒前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
yeyuningzi8 分钟前
Debian 12环境里部署nginx步骤记录
linux·运维·服务器
上辈子杀猪这辈子学IT27 分钟前
【Zookeeper集群搭建】安装zookeeper、zookeeper集群配置、zookeeper启动与关闭、zookeeper的shell命令操作
linux·hadoop·zookeeper·centos·debian
minihuabei32 分钟前
linux centos 安装redis
linux·redis·centos
EasyCVR1 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
lldhsds1 小时前
书生大模型实战营第四期-入门岛-1. Linux前置基础
linux
wowocpp2 小时前
ubuntu 22.04 硬件配置 查看 显卡
linux·运维·ubuntu
山河君2 小时前
ubuntu使用DeepSpeech进行语音识别(包含交叉编译)
linux·ubuntu·语音识别
鹏大师运维2 小时前
【功能介绍】信创终端系统上各WPS版本的授权差异
linux·wps·授权·麒麟·国产操作系统·1024程序员节·统信uos
筱源源2 小时前
Elasticsearch-linux环境部署
linux·elasticsearch