您好,登錄后才能下訂單哦!
下圖是基于UDP協議的客戶端/服務器程序的一般流程:
圖1.1 UDP協議通信流程
UDP套接口是無連接的、不可靠的數據報協議;
既然他不可靠為什么還要用呢?其一:當應用程序使用廣播或多播時只能使用UDP協議;其二:由于他是無連接的,所以速度快。因為UDP套接口是無連接的,如果一方的數據報丟失,那另一方將無限等待,解決辦法是設置一個超時。
建立UDP套接口時socket函數的第二個參數應該是SOCK_DGRAM,說明是建立一個UDP套接口;由于UDP是無連接的,所以服務器端并不需要listen或accept函數。
使用UDP套接字編程可以實現基于TCP/IP協議的面向無連接的通信,它分為服務器端和客戶端兩部分,其主要實現過程如圖1.1所示。
下面介紹UDP網絡編程的詳細函數和過程:
1、socket函數:為了執行網絡輸入輸出,一個進程必須做的第一件事就是調用socket函數獲得一個文件描述符。
----------------------------------------------------------------- |
第一個參數指明了協議簇,目前支持5種協議簇,最常用的有AF_INET(IPv4協議)和AF_INET6(IPv6協議);第二個參數指明套接口類型,有三種類型可選:SOCK_STREAM(字節流套接口)、SOCK_DGRAM(數據報套接口)和SOCK_RAW(原始套接口);如果套接口類型不是原始套接口,那么第三個參數就為0。
2、bind函數:為套接口分配一個本地IP和協議端口,對于網際協議,協議地址是32位IPv4地址或128位IPv6地址與16位的TCP或UDP端口號的組合;如指定端口為0,調用bind時內核將選擇一個臨時端口,如果指定一個通配IP地址,則要等到建立連接后內核才選擇一個本地IP地址。
------------------------------------------------------------------- |
第一個參數是socket函數返回的套接口描述字;第二和第第三個參數分別是一個指向特定于協議的地址結構的指針和該地址結構的長度。
3、recvfrom函數:UDP使用recvfrom()函數接收數據,他類似于標準的read(),但是在recvfrom()函數中要指明目的地址。
------------------------------------------------------------------- |
前三個參數等同于函數read()的前三個參數,flags參數是傳輸控制標志。最后兩個參數類似于accept的最后兩個參數。
4、sendto函數:UDP使用sendto()函數發送數據,他類似于標準的write(),但是在sendto()函數中要指明目的地址。
------------------------------------------------------------------- |
前三個參數等同于函數read()的前三個參數,flags參數是傳輸控制標志。參數to指明數據將發往的協議地址,他的大小由addrlen參數來指定。
server.c程序源碼:
#include <stdio.h> #include <sys/socket.h> #include <stdlib.h> #include <netinet/in.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #define _MAXLINE_ 80 #define _SERV_PORT_ 8000 int main() { struct sockaddr_in server_addr,client_addr; socklen_t cliaddr_len; int sockfd; char buf[_MAXLINE_]; char str[INET_ADDRSTRLEN]; int i, n; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0){ printf("create socket error!...\n"); return -1; } bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(_SERV_PORT_); if(bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0){ printf("bind error!..."); close(sockfd); return 1; } printf("Accepting connections ...\n"); while(1){ cliaddr_len = sizeof(client_addr); //n = recvfrom(sockfd, buf, _MAXLINE_, 0,(struct sockaddr *)&client_addr, &cliaddr_len); n = recvfrom(sockfd, buf, _MAXLINE_, 0,(struct sockaddr *)&client_addr, &cliaddr_len); if(n == -1){ printf("recvfrom error...\n"); exit(1); } printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &client_addr.sin_addr, str,sizeof(str)),ntohs(client_addr.sin_port)); for(i = 0; i < n; i++){ buf[i] = toupper(buf[i]); } n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&client_addr, sizeof(client_addr)); if(n == -1){ printf("sendto error...\n"); } } return 0; }
UDP客戶端程序設計
client.c程序源碼:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #define _MAXLINE_ 80 #define _SERV_PORT_ 8000 int main(int argc, int* argv[]) { struct sockaddr_in servaddr; int sockfd, n; char buf[_MAXLINE_]; char str[INET_ADDRSTRLEN]; socklen_t servaddr_len; sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); servaddr.sin_port = htons(_SERV_PORT_); while(fgets(buf, _MAXLINE_, stdin)!= NULL){ n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)\ &servaddr, sizeof(servaddr)); if(n == -1){ printf("sendto error\n"); } n = recvfrom(sockfd, buf, _MAXLINE_, 0, NULL, 0); if(n == -1){ printf("recvfrom error\n"); } write(STDOUT_FILENO, buf, n); } close(sockfd); return 0; }
運行展示,client發送小寫字母,server收到之后進行大小寫轉換,發回到client,結果如下:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。