UDP學習筆記

有TCP的基礎,學習UDP是很快的。

與TCP程序設計相比較,UDP少了connect、listen以及accept。因爲UDP協議是無連接的,不像TCP需要維護連接的狀態。

在這裏插入圖片描述
建立通訊套解字過程和TCP協議含義相同,不過建立的套接字類型爲數據報套接字(SOCK_DGRAM).

recvfrom()函數:
ssize_t recvfrom(int sock,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);

參數釋義:
from指向本地的數據結構struct sockaddr_in的指針,接收數據時發送方的地址信息放在這個結構中。
fromlen表示第四個參數所指定的內容的長度,可以使用sizeof(struct sockaddr_in)來獲得。

返回值:出錯返回-1。

sendto函數:
ssize_t recvfrom(int sock,const void *buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);

使用這兩個函數的時候要分清楚其中的指針參數。
to指向本地的數據結構struct sockaddr_in的指針,發送數據時接收方的地址信息放在這個結構中。

來兩個簡單的小栗子:

//UDP_S

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define PORT_SERVER 8000
#define BUF_LEN 256

void static udpServer_echo(int s,struct sockaddr *client)
{
    int n;
    char buff[BUF_LEN];
    socklen_t len;
    
    while(1)
    {
        len = sizeof(*client);
        n = recvfrom(s,buff,BUF_LEN,0,client,&len);
        
        sendto(s,buff,n,0,client,len);
    }
}

int main()
{
    int s;
    struct sockaddr_in addr_serv,addr_client;
    
    s = socket(PF_INET,SOCK_DGRAM,0);
    
    memset(&addr_serv,0,sizeof(addr_serv));
    addr_serv.sin_family = PF_INET;
    addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_serv.sin_port = htons(PORT_SERVER);
    
    bind(s,(struct sockaddr *)&addr_serv,sizeof(addr_serv));
    
    udpServer_echo(s,(struct sockaddr *)&addr_client);

    return 0;
}

//UDP_C

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>

#define PORT_SERVER 8000
#define BUF_LEN 256

void static udpServer_echo(int s,struct sockaddr *to)
{
    struct sockaddr_in from;
        
    char buff[BUF_LEN] = "UDP TEST";
    socklen_t len = sizeof(*to);
    
    sendto(s,buff,BUF_LEN,0,to,len);
    n = recvfrom(s,buff,BUF_LEN,0,(struct sockaddr *)&from,&len);
   
    printf("recved:%s\n",buff);
}

int main()
{
    int s;
    struct sockaddr_in addr_serv;
    
    s = socket(PF_INET,SOCK_DGRAM,0);
    
    memset(&addr_serv,0,sizeof(addr_serv));
    addr_serv.sin_family = PF_INET;
    addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
    addr_serv.sin_port = htons(PORT_SERVER);
    
    bind(s,(struct sockaddr *)&addr_serv,sizeof(addr_serv));
    
    udpServer_echo(s,(struct sockaddr *)&addr_serv);

    return 0;
}

UDP程序設計是常見的幾個問題:

1、UDP報文丟失數據
這個是很正常的,追求速度自然要犧牲質量了。
但是上面那個例子來說,如果客戶端發送的數據丟失,服務器會一直等待,直到客戶端的合法數據到來;如果服務器發送的數據丟失,客戶端則會一直阻塞等待服務器的合法數據到來。
在程序運行的過程中是不允許出現這種情況的,所以可以設置超時時間來判斷是否有數據到來。
對於數據丟失的原因,並不能簡單的找出來。

UDP報文丟失的對策還有:a、像三次握手一樣,收到了說一聲,但是未免太麻煩。
b、使用流水號,三發一至。
反正這兩個辦法都會拖慢速度。

2、UDP發送過程中的亂序
UDP協議的數據經過路由器的時候造成了數據順序的混亂,這也是很正常的,誰讓人家本來就不安全嘛。
對於UDP數據亂序的對策:
對於亂序的問題可以在數據段中加入數據報號的方法,這樣在接收到數據的時候只需要對號碼進行簡單的排序就可以恢復秩序。

3、UDP缺乏流量控制
這個倒不是說會消耗很多的上網流量啊。
UDP沒有TCP的滑動窗口的概念,在接收數據的緩衝區滿之後,如果用戶沒有及時取出,則後來的數據會覆蓋之前的數據而導致數據的丟失。

解決方法一般有兩個,一個就是增大緩衝區,一個是採用數據單獨處理,及時處理掉緩衝區中的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章