【嵌入式学习历程17】Linux网络编程(UDP篇)

什么是UDP
UDP即用户数据报协议,它是一种无连接的协议,因此不需要像TCP那样通过三次握手来建立一个连接。同时,一个UDP应用可同步作为应用的客户或服务器方。由于UDP协议并不需要建立一个明确的连接,因此建立UDP应用要比建立TCP应用简单的多。
UDP在数据传输过程中延迟小、数据传输效率高,适合可靠性要求不高的应用程序,或可以保障可靠性的应用程序。通常音频、视频和普通数据在传送时使用UDP较多。

使用
在选择使用协议的时候,选择UDP必须要谨慎。在 网络质量令人十分不满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和 QQ就是使用的UDP协议。

TCP与UDP的比较
为了更好的理解UDP,经常把TCP与UDP拿来做比较,下面我们来对比一下两者的区别。
1、最主要的区别 : TCP是面向连接的传输控制协议,而UDP提供了无连接的数据报服务;
2、TCP具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;UDP在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
3、UDP具有较好的实时性,工作效率较TCP协议高;
4、UDP段结构比TCP的段结构简单,因此网络开销也小。

使用UDP协议的网络编程
先了解一下大致的流程(本人手绘,请不要嫌弃):
【嵌入式学习历程17】Linux网络编程(UDP篇)_第1张图片
看起来有没有似曾相识呢,其实跟TCP协议流程差不多,只不过比TCP简单,因为UDP是一种无连接协议,所以服务器不需要监听(listen)以及接受请求(accept),客户端也不需要连接服务器(connect)

下面用代码来实现基本功能:

/*********************************************
File Name:          UdpServer.c
Author:             huazai
Description:        UDP
Fuction List:
**********************************************/

#include 
#include 
#include 
#include 
#include    
#include 
#include 
#include 

#define PORT 8888       //端口号

struct info
{
    char buf[100];
    int port;
};

int main()
{
    int sockfd, ret, length, j, i = 0;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr[20] = {0};
    struct sockaddr_in tmp_addr;
    struct info RecvBuf;

    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

    bzero(&server_addr, sizeof(server_addr));   //清零初始化
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = PORT;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

    if (-1 == ret)
    {
        perror("bind");
        exit(1);
    }

    while(1)
    {
        length = sizeof(client_addr[0]);
        ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&tmp_addr, &length);    //接收客户端消息

        if (ret < 0)
        {
            perror("recvfrom");
            exit(1);
        }

        printf("Recv From Client %d : %s\n", tmp_addr.sin_port, RecvBuf.buf);   

        if (0 == i)
        {
            client_addr[0].sin_family = tmp_addr.sin_family;
            client_addr[0].sin_port = tmp_addr.sin_port;
            client_addr[0].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
            i++;
        }
        else
        {
            for (j = 0; j < i; j++)
            {
                if (tmp_addr.sin_port == client_addr[j].sin_port)
                {
                    break;
                }

                if (j == i - 1)
                {
                    client_addr[i].sin_family = tmp_addr.sin_family;
                    client_addr[i].sin_port = tmp_addr.sin_port;
                    client_addr[i].sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
                    i++;    
                }
            }
        }

        if(!strcmp(RecvBuf.buf, "bye")) //以bye结束
        {
            break;
        }

        strcat(RecvBuf.buf, "-server"); //服务器将收到的客户端的消息加上"-server"

        for (j = 0; j < i; j++)
        {
            if(RecvBuf.port == client_addr[j].sin_port)
            {
                break;
            }

            if (j == i - 1)
            {
                break;
            }
        }   

        ret = sendto(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&client_addr[j], sizeof(client_addr[j])); //转发给客户端

        if (ret < 0)
        {
            perror("sendto");
            exit(1);
        }

        memset(&RecvBuf, 0, sizeof(RecvBuf));   //清空缓冲区
    }

    return 0;
}
/***************************************************
File Name:              UdpClient.c 
Author:                 huazai
Description:            UDP
Fuction List:         
date:                   2017.12.13  
***************************************************/


#include 
#include 
#include    
#include 
#include 
#include 
#include 
#include 

#define PORT 8888

struct info
{
    char buf[100];
    int port;
};

/* 发送消息 */
void *Send(void *arg)
{
    struct info SendBuf;
    struct sockaddr_in server_addr;
    int ret;

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = PF_INET;
    server_addr.sin_port = PORT;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    while(1)
    {
        scanf("%s %d", SendBuf.buf, &SendBuf.port);

        ret = sendto(*(int *)arg, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));  //发送消息给服务器

        if (ret < 0)
        {
            perror("sendto");
            exit(1);
        }

        if(!strcmp(SendBuf.buf, "bye")) //以bye结束
        {
            break;
        }

        bzero(&SendBuf, sizeof(SendBuf));
    }
}

/* 接收消息 */
void *Recv(void *arg)
{
    while(1)
    {
        struct sockaddr_in server_addr;
        struct info RecvBuf;
        int ret, length;

        length = sizeof(server_addr);
        ret = recvfrom(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);

        if (ret < 0)
        {
            perror("recvfrom");
            exit(1);
        }

        printf("Receive : %s \n", RecvBuf.buf);
    }
}

int main()
{
    int sockfd, ret, length;
    char buf[100] = {0};
    pthread_t tid[2] = {0};
    struct sockaddr_in server_addr;

    sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("socket");
        exit(1);
    }

/* 创建两个线程 */
    ret = pthread_create(&tid[0], NULL, Send, (void *)&sockfd); //线程发送消息
    if (ret < 0)
    {
        perror("create1");
        exit(1);
    }

    ret = pthread_create(&tid[1], NULL, Recv, (void *)&sockfd); //线程接收消息
    if (ret < 0)
    {
        perror("create2");
        exit(1);
    }

    pthread_join(tid[0], NULL); //等待
    pthread_join(tid[1], NULL);

    close(sockfd);

    return 0;
}

你可能感兴趣的:(学习记录)