1. 程式人生 > >UDP程式設計以及與TCP的區別

UDP程式設計以及與TCP的區別

UDP程式設計函式原型:

int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr* my_addr, int addrlen);
/*
與TCP函式原型一樣,參見上一篇部落格。
*/
int recvfrom(int sockfd, void* buf, int len, int flags, struct sockaddr* src_addr, int *addrlen);
/*
在recv的基礎上加上了後兩個引數,因為UDP通訊沒有連線的概念,所以每次讀取資料都需要獲取傳送端的socket地址,即引數src_addr所指的內容,addrlen引數為指定地址的長度。
*/
int sendto(int sockfd, const void* buf, int len, int flags, const struct sockaddr* dest_addr, int addrlen);
/*
在send的基礎上加上了指定接收端的socket地址dest_addr,addrlen引數指定該地址的長度。
*/
int close(int sockfd);

UDP程式設計:
伺服器udpser.c

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>

int main()
{
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in ser, cli;

	memset(&ser, 0, sizeof(ser));
	ser.sin_family = AF_INET;
	ser.sin_port = htons(6500);
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");

	int len = sizeof(struct sockaddr_in);
	int res = bind(sockfd, (struct sockaddr*)&ser, len);
	assert(res != -1);
	char buff[128] = { 0 };

	while (1)
	{
		recvfrom(sockfd, buff, 127, 0, (struct sockaddr*)&cli, &len);
		printf("%s", buff);
		sendto(sockfd, "OK", 3, 0, (struct sockaddr*)&cli, len);
	}
	close(sockfd);
	return 0;
}

客戶端udpcli.c

#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])
{
	if (argc < 3)
	{
		printf("error\n");
		exit(0);
	}
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in cli;
	memset(&cli, 0, sizeof(cli));

	const char *ip = argv[1];
	cli.sin_family = AF_INET;
	cli.sin_port = htons(atoi(argv[2]));
	cli.sin_addr.s_addr = inet_addr(ip);

	char buff[128] = { 0 };
	int len = sizeof(cli);
	printf("start writing\n");
	while (1)
	{
		fgets(buff, 127, stdin);
		if (strncmp(buff, "end", 3) == 0)
		{
			sendto(sockfd, "one cli end\n", 12, 0,
				(struct sockaddr*)&cli, len);
			sleep(1);
			break;
		}
		sendto(sockfd, buff, 127, 0, (struct sockaddr*)&cli, len);

		recvfrom(sockfd, buff, 127, 0, (struct sockaddr*)&cli, &len);
		printf("%s\n", buff);
	}
	close(sockfd);
	return 0;
}

TCP和UDP的區別:
TCP:TCP是面向連線,較為可靠的位元組流服務。所謂位元組流服務,就是傳送資料的次數與接收資料的次數沒有關係,底層資料傳送或接收時,資料可能會被分開或者合併。
如圖:
在這裡插入圖片描述
UDP:UDP是無連線,相對TCP較為不可靠的資料報服務。傳送次數和接收次數相等,所以可能造成,如果一次未將資料讀完,UDP報文段中的資料將丟失。
如圖:
在這裡插入圖片描述
資料的可靠性傳輸:
①所有資料都能到達對端(確認機制和超時重傳機制)
②資料不亂序(TCP報頭中的序號)
③資料不出錯(16位的校驗和,校驗TCP頭部和資料部分)。
在這裡插入圖片描述
詳細TCP頭部結構解釋參見《Linux高效能伺服器程式設計》3.2。