《UNIX网络编程 卷1:套接字联网API》学习笔记——基本UDP套接字编程
生活随笔
收集整理的這篇文章主要介紹了
《UNIX网络编程 卷1:套接字联网API》学习笔记——基本UDP套接字编程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
UNIX網絡編程——基本UDP套接字編程
- 概述
- recvfrom 和 sendto函數
- UDP 回射服務器程序:main 函數
- UDP 回射服務器程序:dg_echo 函數
- UDP 回射客戶程序: main 函數
- UDP 回射客戶程序: dg_cli 函數
- 數據報的丟失
- 驗證接收到的響應
概述
UDP是無連接不可靠的數據報協議。
使用UDP編寫的一些常見的應用程序有:DNS(域名系統)、NFS(網絡文件系統)和 SNMP(簡單網絡管理協議)。
recvfrom 和 sendto函數
#include <sys/socket.h> ssize_t recvfrom(int sockfd, void* buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t *addrlen); ssize_t sendto(int sockfd, const void* buff, size_t nbytes, int flags,const struct sockaddr* to, socklen_t addrlen);均返回:若成功則為讀或寫的字節數,若出錯則為-1前三個參數 sockfd、buff 和 nbytes 等同于 read 和 write 函數的三個參數:描述符、指向讀入或寫成緩沖區的指針和讀寫字節數。
使用sendto、recvfrom發送和接收數據量為0的數據報是允許的。
recvfrom返回0,并不意味著收到對端FIN(sendto,recvfrom使用的場景下沒有連接的概念)。
UDP 回射服務器程序:main 函數
#include "unp.h" int main(int argc, char **argv) {int sockfd;struct sockaddr_in servaddr, cliaddr;/*創建一個UDP套接字*/sockfd = socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT); /*SERV_PORT 服務器的眾所周知端口*/bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr));/*調用函數 dg_echo 來執行服務器的處理工作*/dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr)); }UDP 回射服務器程序:dg_echo 函數
#include "unp.h" void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen) {int n;socklen_t len;char mesg[MAXLINE];/*該函數是一個簡單的循環,它使用 recvfrom 讀入下一個到達服務器端口的數據報,再使用 sendto 把它發送回發送者*/for ( ; ;){len = clilen;n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);sendto(sockfd, mesg, n, 0, pcliaddr, len);} }圖中總結了TCP客戶/服務器在兩個客戶與服務器建立連接時情形。
服務器主機上有兩個已連接套接字,其中每一個都有各自的套接字接收緩沖區。
下圖展示了兩個客戶發送數據報到UDP服務器的情形。
UDP 回射客戶程序: main 函數
#include "unp.h" int main(int argc, char **argv) {int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");/*把服務器的IP地址和端口號填入一個IPv4的套接字地址結構*/bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);inet_pton(AF_INET, argv[1], &servaddr.sin_addr);/*創建一個UDP套接字,然后調用dg_cli*/sockfd = socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));exit(0); }UDP 回射客戶程序: dg_cli 函數
#include "unp.h" void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) {int n;char sendline[MAXLINE], recvline[MAXLINE + 1];/*客戶處理循環中的四個步驟*//*使用 fgets 從標準輸入讀入一個文本行*/while (fgets(sendline, MAXLINE, fp) != NULL){/*使用 sendto 將該文本行發送給服務器*/sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);/*使用 recvfrom 讀回服務器的回射*/n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);recvline[n] = 0; /*null terminate*//*使用 fputs 把回射的文本行顯示到標準輸出*/fputs(recvline, stdout);} }數據報的丟失
如果一個客戶數據報丟失(如,被客戶主機與服務器主機之間的某個路由器丟棄),客戶將永遠阻塞于 dg_cli 函數中的 recvfrom 調用,等待一個永遠不會到達的服務器應答。
防止這樣永久阻塞的一般方法是給客戶的 recvfrom 調用設置一個超時。
驗證接收到的響應
recvfrom 返回的IP地址(UDP數據報的源IP地址)不是我們所發送數據報的目的IP地址。
保證應答的源地址與請求的目的地址相同的方法:
- 一個解決辦法是:得到由 recvfrom 返回的IP地址后,客戶通過在DNS中查找服務器主機的名字來驗證該主機的域名(而不是它的IP地址)。
- 另一個解決辦法是:UDP服務器給服務器主機上配置的每個IP地址創建一個套接字,用bind捆綁每個IP地址到各自的套接字,然后在所有這些套接字上使用 select (等待其中任何一個變得可讀),再從可讀的套接字給出應答。
學習參考資料:
《UNIX網絡編程 卷1:套接字聯網API》 第3版總結
以上是生活随笔為你收集整理的《UNIX网络编程 卷1:套接字联网API》学习笔记——基本UDP套接字编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [FROM VIJOS]安装服务器
- 下一篇: 张小龙《微信背后的产品观》之PPT完整文