03 Linux環境下的UDP編程

插座第三個參數傳0,表示默認協議,流式協議的典型代表就是TCP協議,報式協議的典型代表就是UTP協議。

名詞解釋:

BSD:(Berkeley Software Distribution 伯克利發佈的軟件套件),主要是網絡部分。

本地套接字:

本地套接字是的的的的Unix中的中進程間通訊方式,支持進程間的通信,但不能使用在跨計算機的通信中,服務端與客戶端的通信流程基本與網絡套接字一致,但在形式上有兩點不同:

  1. 創建插座時,傳入的域參數不同。域參數應該傳入本地套接字AF_UNIX,AF_LOCAL或AP_UNIX,PF_LOCAL。
    1. AF:地址族,一般傳入地址時使用。
    2. PF:協議族,一般傳入協議時使用。
    3. 但是宏定義的值相同,一般可以混用。
  2. 綁定的地址需要使用sockaddr_un結構體,struct sockaddr_un結構有兩個參數:sun_family,sun_path.sun_family只能是AF_LOCAL或AF_UNIX,而sun_path是本地文件的路徑。通常將文件放在/ tmp目錄下。
    1. addr.sun_family = AF_UNIX;
    2. 的的的strcpy(addr.sun_path中中中,“server.sock”);
    3. ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));
  3. 所以還需要對文件進行驗證,如果文件存在綁定就會報錯。

         addr.sun_family = AF_UNIX;
         的strcpy(addr.sun_path中,“server.sock”);
         ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));

 

參考:https//www.cnblogs.com/hnrainll/archive/2011/04/24/2026433.html

Linux下的UDP套接字編程

UDP協議一般用於即時通訊的應用開發,它們對於數據的及時性要求較高,TCP的連接,驗證等機制都會降低數據的傳送效率。但考慮到數據的完整性問題,一些大型網絡公司就會使用到udp + tcp的形式,在傳輸層使用UDP,在應用層使用自定義的協議,添加類似於TCP的校驗方式,彌補UDP的丟包現象。

彌補UDP丟包的應用層方法,可以改變數據接收端緩衝區的大小,儘量減少緩衝區已滿造成數據丟失的現象。

int n = 220 * 1024;//這是一個在應用中得出的最優值。
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));

兩個函數:服務端參數:

recvfrom(connfd,buf,strlen(buf),0,(struct sockaddr *)&addr,&len); //此處的地址與LEN都是傳入傳出參數,獲取的客戶端的信息,用作之後的SENDTO函數參數。

sendto(sockfd,buf,n,0,(struct sockaddr *)&addr,len); //按照指定的地址將數據發送給客戶端,所以此處的LEN參數不需要取地址。若客戶端不先行發送數據,服務端就無法得知其地址,無法主動發送數據。

UDP實現廣播

TCP / IP協議棧中,只有UDP可以廣播。

網管地址(網管號):主機號爲全0的IP地址所有訪問外網的請求都由這個網管轉發,當然也可以在此網關處設置限制。

廣播地址:主機號爲全1的IP地址爲廣播地址當發出一個目的地址爲廣播地址的分組(封包)時,它將被分發給該網段上的所有計算機。

IP:192.168.42.255(廣播)

IP:192.168.42.1(網管)

的的sockfd默認不支持廣播,需要通過調用setsockopt的的函數進行修改,開放廣播權限。

flag = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));

需要注意:

  1. 127.0.0.0是本地會環地址,從網卡的發送端出去,在本地接收端返回,可以用於測試本地的C / S程序。
  2. 在服務器中,0.0.0.0指的是本機上的所有(任意)IPV4地址,如果一個主機有兩個IP地址,192.168.1.1和10.1.2.1,並且該主機上的一個服務監聽的地址是0.0 .0.0,那麼通過兩個IP地址都能夠訪問該服務。當然在服務器端也可以使用,還可以用INADDR_ANY(宏定義值爲0)來代替。
  3. 然而對於Linux的發行版本的實際實現中,需要使用客戶端需要使用任意地址,不然使用本地某個具體地址就會接收不到廣播。
  4. 在同一局域網內的不同主機可以擁有兩個相同的IP,即IP衝突。
  5. 在同一臺計算機中的IP地址與端口號不能在程序運行時重用,在不同計算機中可以使用相同的端口號實現廣播,發送方向也可以指向同一端口號。

注意:客戶端地址需要使用任意,否則接收不到廣播信息。這是必須的。

貼出以下實現代碼:

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#include <sys/socket.h>
#include <arpa/inet.h>

#define SIZE 128

#define BROADCAST_IP "192.168.16.255" //C類IP地址
#define CLIENT_PORT 9000

#define SERVER_PORT 8000

int main(void)
{
	int ret = -1;
	int sockfd = -1;
	int flag = -1;
	char buf[SIZE];
	struct sockaddr_in addr;
	struct sockaddr_in from;
	socklen_t len = sizeof(from);
	
	//1.創建套接字
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd) {
		perror("socket");
		return 1;
	}
	printf("sockfd :%d\n", sockfd);
	//2.綁定
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(SERVER_PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
	if (-1 == ret) {
		perror("bind");
		return 1;
	}
	
	flag = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));
	/* 構造client地址 IP + 端口,因爲是服務器主動發送數據,
	 * 所以需要知道客戶端的端口號,與之前基於TCP的C/S模型相比,
	 * 之前的一般由客戶端主動訪問服務端,而客戶端的端口號是隨機獲取的。
	 * 而對於廣播,是一種不同的業務需求,
	 * 需要服務端向範圍IP端口發送數據,這時候就很有必要知道客戶端程序的端口號。
	 * 所以此時服務端的端口號反倒不重要了,可以隨機獲取。*/
	memset(&from, 0, sizeof(from));
	from.sin_family = AF_INET;
	from.sin_port = htons(9000);
	inet_pton(AF_INET, BROADCAST_IP, &from.sin_addr.s_addr);

	//3.循環接收客戶端數據
	int i = 0;
//	memset(buf, 0, SIZE);
	while (1) {
		sprintf(buf, "Drink %d glasses of water", i++);//有一端添加換行符即可。
		sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&from, sizeof(from));
		printf("--->發出數據\n");
		
		usleep(100000);
	}

	//4.關閉文件描述符
	close(sockfd);
	
	return 0;
}


client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#include <arpa/inet.h>
#include <sys/socket.h>

#define SIZE 128
#define CLIENT_PORT 9000

int main(void)
{
	int ret = -1;
	int sockfd = -1;
	char buf[SIZE];
	struct sockaddr_in addr;
	int len = -1;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == sockfd) {
		perror("socket");
		return 1;
	}

	//初始化本地地址
	//相當於INADDR_ANY
	//區分127.0.0.1
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(CLIENT_PORT);
	ret = inet_pton(AF_INET, "0.0.0.0", &addr.sin_addr.s_addr);
	if (-1 == ret) {
		printf("inet_pton");
		return 1;
	}
	ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
	if (0 == ret) 
		printf("...bind ok...\n");
	
	memset(buf, 0, SIZE);
	/* 從網絡中讀取的數據,傳輸過來的字符串結束標記的'\0'是會被忽略的。
	 * 所以一定要注意將接受端的容器清空,這樣才能夠保證不讀取客戶端未
	 * 清空的buf後的錯誤數據。所以,最重要的問題就是:
	 *		1.網絡傳輸中尾0被忽略。
	 *		2.客戶端接收時沒有將容器即使清零。*/
	while (1) {
		len = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, 0);
		printf("ret = %d\n", len);
		printf("--->%s\n", buf);
	}
	
	close(sockfd);
	return 0;
}

TCP UDP與

TCP:面向連接的可靠數據包傳遞------對當前網絡環境做完全彌補

    優點:穩定

  1. 數據穩定:------丟包回傳的回執機制。
  2. 速率穩定:------使用TCP方式傳遞的數據包在網絡穩定的情況下經過的路由是固定的。
  3. 流量穩定:------滑動窗口,對每次發送的數據量進行限制。

    缺點:

  1. 效率低:回執
  2. 傳輸速度慢:滑動窗口

    使用場景:

  1. 大文件傳輸
  2. 重要文件傳輸

UDP:無連接的不可靠報文傳遞------對當前網絡環境做完全不彌補,還原當前的網絡狀態。

    優點:效率高,速度快

    缺點:不穩定:數據,速率,流量。

    使用場景:對實時性要求較高。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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