UDP实现服务器通信

UDP协议

UDP协议简介

  UDP协议提供了一种面向无连接模式的通信。由于这种特性,使用UDP协议进行传输时的开销更小,但同时并不能保证被传输的数据能够到达目的地。UDP建立通信连接不需要借助三次握手和四次挥手,也就意味着TCP建立连接的accept函数和connect函数将不会被用到。

TCP/UDP优缺点

TCPUDP
面向连接,可靠数据包传输无连接,不可靠数据包传输
对于不稳定的网络层,采取完全弥补的通信方式,丢包重传采取完全不弥补的通信方式,默认还原网络状态
只能有两个端点,实现一对一的通信支持一对一、一对多、多对一、和多对多的通信
优点缺点使用场景
TCP数据传输流量、速度、顺序稳定传输速度慢,效率低,资源开销大数据完整性高,不追求效率。例如:大数据传输、文件传输
UDP传输速度快,效率高,资源开销小数据传输流量、速度、顺序不稳定时效性要求较高场合,稳定性其次,系统资源较少的嵌入式系统,网络条件稳定的内部局域网,IP与端口号都固定的情况。例如:游戏、视频会议、视频电话【应用层上数据校验协议,弥补udp传输不可靠的不足】

通信流程

step1:调用socket函数建立套接字, sockfd = socket(AF_INET, SOCK_DGRAM, 0),这里SOCK_DGRAM表示数据报套接字传输,而在TCP协议中采用SOCK_STREAM,表示流套接字传输。

step2:调用bind函数绑定地址结构,绑定服务端的IP地址和端口号。

step3:调用listen函数设置监听上限(可有可无)

step4:循环读取客户端数据,调用recvfrom函数,进行大小写转换,将读取到的数据发送回客户端。

step5:调用close函数关闭连接。

recvfrom函数

【recv函数、send函数只能用于TCP通信】

函数原型: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

参数:

​  sockfd:套接字

  buf:缓冲区地址

  len:缓冲区大小

  flags:0-

  src_addr:(struct sockaddr *)&addr,传出参数,对端地址结构

  addrlen:传入传出参数

返回值:

  成功:成功接收的数据字节数

  失败:-1:errno 0:对端关闭

sendto函数

函数原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

参数:

  sockfd:套接字

  buf:存储数据的缓冲区

  len:数据长度

  flags:0-

  src_addr:(struct sockaddr *)&addr,传出参数,目标地址结构

  addrlen:地址结构长度

返回值:

  成功:成功写出的数据字节数

  失败:-1:errno

UDP实现客户端服务端通信

服务端程序

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(void)
{
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    int sockfd;
    char buf[BUFSIZ];
    char str[INET_ADDRSTRLEN];
    int i, n;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(SERV_PORT);

    bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    printf("Accepting connections ...\n");
    while (1) {
        clie_addr_len = sizeof(clie_addr);
        
        n = recvfrom(sockfd, buf, BUFSIZ,0, (struct sockaddr *)&clie_addr, &clie_addr_len);
        if (n == -1)
            perror("recvfrom error");

        printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
                ntohs(clie_addr.sin_port));

        for (i = 0; i < n; i++)
            buf[i] = toupper(buf[i]);

        n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&clie_addr, sizeof(clie_addr));
        if (n == -1)
            perror("sendto error");
    }
    close(sockfd);

    return 0;
}

客户端程序

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    int sockfd, n;
    char buf[BUFSIZ];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    while (fgets(buf, BUFSIZ, stdin) != NULL) {
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (n == -1)
            perror("sendto error");

        n = recvfrom(sockfd, buf, BUFSIZ, 0, NULL, 0);         //NULL:不关心对端信息
        if (n == -1)
            perror("recvfrom error");

        write(STDOUT_FILENO, buf, n);
    }

    close(sockfd);

    return 0;
}

运行结果

服务端:
请添加图片描述
客户端1:
请添加图片描述
客户端2:
请添加图片描述

参考

https://blog.csdn.net/fanle93/article/details/90666484

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值