Linux 網路編程——UDP編程

來源:互聯網
上載者:User

標籤:網路編程   udp編程   cs   

概述

UDP 是 User Datagram Protocol 的簡稱, 中文名是使用者資料包通訊協定,是一個簡單的面向資料報的運輸層協議,在網路中用於處理資料包,是一種不需連線的協議。UDP 不提供可靠性的傳輸,它只是把應用程式傳給 IP 層的資料報發送出去,但是並不能保證它們能到達目的地。由於 UDP 在傳輸資料報前不用在客戶和伺服器之間建立一個串連,且沒有逾時重發等機制,故而傳輸速度很快。


UDP 有如下的特點:

1)郵件系統服務模式的抽象(可通過郵件模型來進行對比)

2)每個分組都攜帶完整的目的地址

3)發送資料之前不需要建立連結

4)不對資料包的順序進行檢查,不能保證分組的先後順序

5)不進行分組出錯的恢複和重傳

6)不保證資料轉送的可靠性



在網路品質令人十分不滿意的環境下,UDP 協議資料包丟失會比較嚴重。但是由於 UDP 的特性:它不屬於串連型協議,因而具有資源消耗小,處理速度快的優點,所以通常音頻、視頻和普通資料在傳送時使用 UDP 較多,因為它們即使偶爾丟失一兩個資料包,也不會對接收結果產生太大影響。比如我們聊天用的 ICQ 和 QQ 就是使用的 UDP 協議。


UDP 編程的 C/S 架構



UDP 用戶端程式對比於寫信模型,用戶端相當於寄信人,要想成功給人寄信,信封上必須寫上對方的地址。

ssize_t sendto(int sockfd,

const void *buf,

size_t nbytes,

int flags,

const struct sockaddr *to,        

socklen_t addrlen );

功能:

向 to 結構體指標中指定的 ip,發送 UDP 資料,可以發送 0 長度的 UDP 資料包

參數:

sockfd:通訊端

buf:發送資料緩衝區

nbytes:發送資料緩衝區的大小

flags:一般為 0

to:指向目的主機地址結構體的指標

addrlen:to 所指向內容的長度

返回值:

成功:發送資料的長度

失敗: -1


這裡通過 Windows 的網路調試助手和虛擬機器中的 ubuntu 用戶端程式進行通訊,網路調試助手下載請點此處。


Windows 的網路調試助手作為伺服器,接收用戶端的請求,調試助手配置如下:



虛擬機器中 ubuntu 的 UDP 用戶端程式:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int main(int argc, char *argv[]){unsigned short port = 8080;//伺服器連接埠char *server_ip = "10.221.20.10";//伺服器ip地址if( argc > 1 )// main函數傳參,伺服器ip地址{server_ip = argv[1];}if( argc > 2 )// main函數傳參,伺服器連接埠{port = atoi(argv[2]);}int sockfd;sockfd = socket(AF_INET, SOCK_DGRAM, 0);   //建立UDP通訊端if(sockfd < 0){perror("socket");exit(-1);}// 通訊端地址struct sockaddr_in dest_addr;bzero(&dest_addr, sizeof(dest_addr));// 清空內容dest_addr.sin_family = AF_INET;// ipv4dest_addr.sin_port   = htons(port);// 連接埠轉換inet_pton(AF_INET, server_ip, &dest_addr.sin_addr);// ip地址轉換printf("send data to UDP server %s:%d!\n", server_ip, port);while(1){char send_buf[512] = "";fgets(send_buf, sizeof(send_buf), stdin);//擷取輸入send_buf[strlen(send_buf)-1] = '\0';//發送資料int len = sendto(sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));printf("len = %d\n", len);}close(sockfd);return 0;}


運行結果如下:


UDP 用戶端注意點:

1)本地IP、本地連接埠(我是誰)

2)目的IP、目的連接埠(發給誰)

3)在用戶端的代碼中,我們只設定了目的IP、目的連接埠

4)用戶端的本地 ip、本地 port 是我們調用 sendto 的時候 linux 系統底層自動給用戶端分配的;分配連接埠的方式為隨機分配,即每次運行系統給的 port 不一樣。


UDP 伺服器程式

UDP網路程式想要收取資料需什麼條件?

1)確定的 ip 地址

2)確定的連接埠(port)

這正如,我要收到別人寄過來的信,我必須告訴別人我的地址(ip),同時告訴別人我我的公寓信箱號(連接埠)。


接收端使用 bind() 函數,來完成地址結構與 socket 通訊端的綁定,這樣 ip、port 就固定了,發送端在 sendto 函數中指定接收端的 ip、port,就可以發送資料了。


需要標頭檔:#include <sys/socket.h>

int bind(    int sockfd,

const struct sockaddr *myaddr,

socklen_t addrlen );

功能:

將本地協議地址與 sockfd 綁定,這樣 ip、port 就固定了

參數:

sockfd: socket 通訊端

myaddr: 指向特定協議的地址結構指標

addrlen:該地址結構的長度

返回值:

成功:返回 0

失敗:-1


使用執行個體如下:

// 本網地址struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr));// 清空結構體內容my_addr.sin_family = AF_INET;// ipv4my_addr.sin_port   = htons(port);// 連接埠轉換my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 綁定網卡所有ip地址,INADDR_ANY為通配地址,值為0printf("Binding server to port %d\n", port);int err_log;err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); // 綁定if(err_log != 0){perror("bind");close(sockfd);exit(-1);}

綁定連接埠有些需要注意的問題,請看《綁定( bind )連接埠需要注意的問題》。


ssize_t recvfrom(   int sockfd, void *buf,    

size_t nbytes,int flags,

struct sockaddr *from, 

socklen_t *addrlen );

功能:

接收 UDP 資料,並將源地址資訊儲存在 from 指向的結構中

參數:

sockfd:通訊端

buf:接收資料緩衝區

nbytes:接收資料緩衝區的大小

flags:通訊端標誌(常為 0)

from:源地址結構體指標,用來儲存資料的來源

addrlen:from 所指內容的長度

返回值:

成功:接收到的長度

失敗: -1


ubuntu 中的伺服器程式如下:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int main(int argc, char *argv[]){unsigned short port = 8000;// 本地連接埠if(argc > 1){port = atoi(argv[1]);}int sockfd;sockfd = socket(AF_INET, SOCK_DGRAM, 0);// 建立通訊端if(sockfd < 0){perror("socket");exit(-1);}// 本網地址struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr));// 清空結構體內容my_addr.sin_family = AF_INET;// ipv4my_addr.sin_port   = htons(port);// 連接埠轉換my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 綁定網卡所有ip地址,INADDR_ANY為通配地址,值為0printf("Binding server to port %d\n", port);int err_log;err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); // 綁定if(err_log != 0){perror("bind");close(sockfd);exit(-1);}printf("receive data...\n");while(1){int recv_len;char recv_buf[512] = "";struct sockaddr_in client_addr;char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16socklen_t cliaddr_len = sizeof(client_addr); // 接受資料recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port));printf("data(%d):%s\n",recv_len,recv_buf);}close(sockfd);return 0;}

Windows 的網路調試助手作為用戶端,給 ubuntu 中的伺服器發送資料,調試助手配置如下:



運行結果如下:



範例程式碼下載請點此處。

Linux 網路編程——UDP編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.