UNP總結 Chapter 8 基本UDP通訊端編程

來源:互聯網
上載者:User

 

1.概述

使用UDP編寫的一些常用應用程式有:DNS(網域名稱系統)、NFS(網路檔案系統)和SNMP(簡易網路管理通訊協定)

給出典型的UDP客戶/伺服器程式的函數調用:

 

 

 

2.recvfrom和sendto函數

兩個函數類似於標準的read和write函數,不過需要三個額外的參數

#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的參數to是一個含有資料將發往的協議地址(例如IP地址和連接埠號碼)的套介面地址結構,它的大小由addrlen來指定。函數recvfrom用資料報寄件者的協議地址裝填由from所指的套介面地址結構,儲存在此套介面地址結構中的位元組數也以addrlen所指的整數返回給調用者。注意,sendto的最後一個參數是一個整數值,而recvfrom的最後一個參數值是一個指向整數值的指標(值-結果參數)。

recvfrom的最後兩個參數類似於accept的最後兩個參數:返回時套介面地址結構的內容告訴我們是誰發送了資料報(UDP情況下)或是誰發起了串連(TCP情況下)。sendto的最後兩個參數類似於connect的最後兩個參數:我們用資料報將發往(UDP情況下)或與之建立串連(TCP情況下)的協議地址來裝填套介面地址結構。

寫一個長度為0的資料報是可行的,這也意味著對於資料報協議,recvfrom返回0值也是可行的;它不表示對方已經關閉了串連,這與TCP套介面上的read返回0的情況不同。由於UDP是不需連線的,這就沒有諸如關閉UDP串連之類的事情。

 PS:預設情況recvfrom函數沒有接收到對方資料時候是阻塞的

 

 

 

3.UDP的connect函數

 我們可以給UDP套介面調用connect,但這樣做的結果卻與TCP串連毫不相同:沒有三路握手過程。核心只是記錄對方的IP地址和連接埠號碼,它們包含在傳遞給connect的套介面地址結構中,並立即返回給調用進程。

 

對於已串連UDP套介面,與預設的未串連套介面相比,發生了三個變化:

1).我們再也不能給輸出操作指定宿IP和連接埠號碼,也就是說我們不使用sendto,而改用write或send,寫到已串連UDP套介面上的任何內容都自動發送到由connect指定的協議地址(例如IP地址和連接埠號碼)

2).我們不必使用recvfrom以獲悉資料報的寄件者,而改用read,recv或recvmsg,在一個已串連UDP套介面上由核心為輸入操作返回的資料報僅僅是那些來自connect所指定協議地址的資料報。目的地為這個已串連UDP套介面的本地協議地址,發源地卻不是該套介面早先connect到的協議地址的資料報,不會投遞到該套介面。這樣就限制了一個已串連UDP套介面而且僅能與一個對端交換資料報。

3).由已串連的UDP套介面引發的非同步錯誤返回給他們所在的進程,而未串連UDP通訊端不接受任何非同步錯誤。

 

 

擁有一個已串連的UDP通訊端的進程出於下列目的再次調用connect

  • 指定新的IP地址和連接埠號碼
  • 斷開套介面

第一個目的(即給一個已串連UDP套介面指定新的對端)不同於TCP套介面中connect的使用:對於TCP套介面,connect只能調用一次。

為了斷開一個已connect的UDP套介面串連,我們再次調用connect時把套介面地址結構的地址簇成員(sin_family)設定為AF_UNSPEC。 這麼做可能返回一個EAFNOSUPPORT錯誤,不過沒有關係。 使得套介面中斷連線的是在已串連UDP套介面上調用connect的進程。

 

 

4.UDP回射服務程式

 

1).main函數

#include     "unp.h"intmain(int argc, char **argv){    int     sockfd;    struct sockaddr_in servaddr, cliaddr;    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);    Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));    dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));}

 

2).dg_echo函數

#include     "unp.h"voiddg_echo(int sockfd, SA *pcliaddr, socklen_t clilen){    int     n;    socklen_t len;    char    mesg[MAXLINE];    for ( ; ; ) {        len = clilen;        n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);        Sendto(sockfd, mesg, n, 0, pcliaddr, len);    }}

 

5.UDP回射客戶程式

1).main函數

#include     "unp.h"intmain(int argc, char **argv){    int     sockfd;    struct sockaddr_in servaddr;    if(argc != 2)       err_quit("usage: udpcli <IPaddress>");    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(SERV_PORT);    Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);    dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));    exit(0);}

 

2).dg_cli函數(非connect)

#include     "unp.h"voiddg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){    int     n;    char    sendline[MAXLINE], recvline[MAXLINE + 1];    while (Fgets(sendline, MAXLINE, fp) != NULL) {        Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);        n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);        recvline[n] = 0;        /* null terminate */        Fputs(recvline, stdout);    }}

 

3).dg_cli函數(connect)

#include     "unp.h"voiddg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen){    int     n;    char    sendline[MAXLINE], recvline[MAXLINE + 1];    Connect(sockfd, (SA *) pservaddr, servlen);    while (Fgets(sendline, MAXLINE, fp) != NULL) {        Write(sockfd, sendline, strlen(sendline));        n = Read(sockfd, recvline, MAXLINE);        recvline[n] = 0;        /* null terminate */        Fputs(recvline, stdout);    }}

 

 

6.使用select函數的TCP和UDP回射伺服器程式

#include     "unp.h"intmain(int argc, char **argv){    int     listenfd, connfd, udpfd, nready, maxfdp1;    char    mesg[MAXLINE];    pid_t   childpid;    fd_set  rset;    ssize_t n;    socklen_t len;    const int on = 1;    struct sockaddr_in cliaddr, servaddr;    void    sig_chld(int);        /* create listening TCP socket */    listenfd = Socket(AF_INET, SOCK_STREAM, 0);    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    servaddr.sin_port = htons(SERV_PORT);    Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));    Listen(listenfd, LISTENQ);         /* create UDP socket */    udpfd = 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);    Bind(udpfd, (SA *) &servaddr, sizeof(servaddr));    Signal(SIGCHLD, sig_chld);     /* must call waitpid() */    FD_ZERO(&rset);    maxfdp1 = max(listenfd, udpfd) + 1;    for ( ; ; ) {        FD_SET(listenfd, &rset);        FD_SET(udpfd, &rset);        if ( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {            if (errno == EINTR)                continue;     /* back to for() */            else                err_sys("select error");         }         if (FD_ISSET(listenfd, &rset)) {             len = sizeof(cliaddr);             connfd = Accept(listenfd, (SA *) &cliaddr, &len);             if ( (childpid = Fork()) == 0) { /* child process */                 Close(listenfd);     /* close listening socket */                 str_echo(connfd);    /* process the request */                 exit(0);              }              Close(connfd);     /* parent closes connected socket */         }          if (FD_ISSET(udpfd, &rset)) {             len = sizeof(cliaddr);             n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA *) &cliaddr, &len);              Sendto(udpfd, mesg, n, 0, (SA *) &cliaddr, len);         }    }}

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.