UDP服務器
傳輸層主要應用的協議模型有兩種,一種是TCP協議,另外一種則是UDP協議。TCP協議在網絡通信中占主導地位,絕大多數的網絡通信藉助TCP協議完成數據傳輸。但UDP也是網絡通信中不可或缺的重要通信手段。
相較於TCP而言,UDP通信的形式更像是發短信。不需要在數據傳輸之前建立、維護連接。只專心獲取數據就好。省去了三次握手的過程,通信速度可以大大提高,但與之伴隨的通信的穩定性和正確率便得不到保證。因此,我們稱UDP爲“無連接的不可靠報文傳遞”。
那麼與我們熟知的TCP相比,UDP有哪些優點和不足呢?由於無需創建連接,所以UDP開銷較小,數據傳輸速度快,實時性較強。多用於對實時性要求較高的通信場合,如視頻會議、電話會議等。但隨之也伴隨着數據傳輸不可靠,傳輸數據的正確率、傳輸順序和流量都得不到控制和保證。所以,通常情況下,使用UDP協議進行數據傳輸,爲保證數據的正確性,我們需要在應用層添加輔助校驗協議來彌補UDP的不足,以達到數據可靠傳輸的目的。
與TCP類似的,UDP也有可能出現緩衝區被填滿後,再接收數據時丟包的現象。由於它沒有TCP滑動窗口的機制,通常採用如下兩種方法解決:
- 服務器應用層設計流量控制,控制發送數據速度。
- 藉助setsockopt函數改變接收緩衝區大小。如:
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int n = 220x1024
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
C/S模型-UDP
server端
1 #include<stdio.h>
2 #include<netinet/in.h>
3 #include<stdlib.h>
4 #include<sys/types.h>
5 #include<sys/socket.h>
6 #include<assert.h>
7 #include<arpa/inet.h>
8 #include<string.h>
9 #include<ctype.h>
10 #define BUFF_SIZE 64
11 int main(int argc, char*argv[])
12 {
13 if(argc < 3)
14 {
15 printf("argc less 3\n");
16 exit(1);
17 }
18 const char * ip=argv[1];
19 int port=atoi(argv[2]);
20
21 struct sockaddr_in saddr,caddr;
22
23 int sfd = socket(AF_INET,SOCK_DGRAM,0);
24
25 saddr.sin_family=AF_INET;
26 saddr.sin_port=htons(port);
27 inet_pton(AF_INET,ip,&saddr.sin_addr.s_addr);
28 int ret = bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr));
29 assert(ret != -1);
30
31 char buff[BUFF_SIZE],str[BUFF_SIZE];
32 int i;
33 memset(buff,'\0',BUFF_SIZE);
34 while(1)
35 {
36 socklen_t len = sizeof(caddr);
37 ret = recvfrom(sfd,buff,BUFF_SIZE-1,0,(struct sockaddr*)&caddr,&len);
38 assert(ret!=-1);
39 printf("client ip = %s port=%d\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,str,
40 sizeof(str)),ntohs(caddr.sin_port));
41
42 for(i=0;i<BUFF_SIZE;++i)
43 buff[i]=toupper(buff[i]);
44
45 ret = sendto(sfd,buff,ret,0,(struct sockaddr*)&caddr,len);
46 assert(ret !=-1);
47 printf("%s\n",buff);
48 }
49
50 return 0;
51 }
client端
1 #include<stdio.h>
2 #include<netinet/in.h>
3 #include<stdlib.h>
4 #include<sys/types.h>
5 #include<sys/socket.h>
6 #include<assert.h>
7 #include<arpa/inet.h>
8 #include<string.h>
9 #include<ctype.h>
10 #define BUFF_SIZE 64
11 int main(int argc, char*argv[])
12 {
13 if(argc < 3)
14 {
15 printf("argc less 3\n");
16 exit(1);
17 }
18 const char * ip=argv[1];
19 int port=atoi(argv[2]);
20
21 struct sockaddr_in saddr;
22 saddr.sin_family=AF_INET;
23 saddr.sin_port=htons(port);
24 inet_pton(AF_INET,ip,&saddr.sin_addr.s_addr);
25
26 int cfd = socket(AF_INET,SOCK_DGRAM,0);
27
28 char buff[BUFF_SIZE],str[BUFF_SIZE];
29 int i;
30 memset(buff,'\0',BUFF_SIZE);
31 while(fgets(buff,BUFF_SIZE-1,stdin)!=NULL)
32 {
33
34 socklen_t len = sizeof(saddr);
35 int ret = sendto(cfd,buff,sizeof(buff),0,(struct sockaddr*)&saddr,len);
36 assert(ret !=-1);
37 printf("已經發送:%s\n",buff);
38 ret = recvfrom(cfd,buff,BUFF_SIZE-1,0,NULL,NULL);
39 assert(ret!=-1);
40 printf("%s\n",buff);
41
42 }
43
44 return 0;
45 }
結果分析
client1發送:
yan@ubuntu:~/net/11UDP$ ./client 127.0.0.1 8888
hello
已經發送:helloHELLO
client2發送:
hellohello
已經發送:hellohello
HELLOHELLO
server接收:
client ip = 127.0.0.1 port=59024
HELLOclient ip = 127.0.0.1 port=34412
HELLOHELLO