UDP:用戶數據報協議,它不提供可靠傳輸,只負責數據傳輸,是無連接的
服務器端:
因udp是無連接的,因此不用將套接字設爲監聽狀態
1.創建套接字使用socket(int domain,int type,int protocol)函數
2.將套接字信息填充到內核,進行綁定
3.利用recvfrom()函數與客戶端進行數據通信
recvfrom函數原型:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
從(已連接)套接口上接收數據,並獲取數據發送方的地址。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/types.h> 5 #include<arpa/inet.h> 6 #include<netinet/in.h> 7 #include<sys/socket.h> 8 9 void Usage(char *proc) 10 { 11 printf("Usage:%s [ip] [port]\n",proc); 12 } 13 int main(int argc,char* argv[]) 14 { 15 if(argc!=3) 16 { 17 Usage(argv[0]); 18 exit(1); 19 } 20 21 int sock=socket(AF_INET,SOCK_DGRAM,0); 22 if(sock < 0) 23 { 24 perror("socket"); 25 exit(2); 26 } 27 int _port=atoi(argv[2]); 28 char* _ip=argv[1]; 29 struct sockaddr_in client; 30 client.sin_family=AF_INET; 31 client.sin_port=htons(_port); 32 client.sin_addr.s_addr=inet_addr(_ip); 33 socklen_t len=sizeof(client); 34 if((bind(sock,(struct sockaddr*)&client,len))<0) 35 { 36 perror("bind"); 37 return -1; 38 } 39 int done=0; 40 char buf[1024]; 41 while(!done) 42 { 43 memset(buf,'\0',sizeof(buf));
44 ssize_t _size=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&c lient,&len);
45 if(_size>0)
46 {
47 buf[_size]='\0';
48 printf("[[ip:%s] [port:%d]]:client#%s",inet_ntoa(client.sin_addr ),ntohs(client.sin_port),buf);
49 }else if(_size==0)
50 {
51 printf("client quit...\n");
52 exit(2);
53 }else
54 {
55 perror("recvfrom");
56 return 1;
57 }
58 }
59
60 return 0;
61 }
客戶端:
使用sendto()函數,發送數據進行傳輸
sendto()函數原型:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/types.h> 5 #include<arpa/inet.h> 6 #include<netinet/in.h> 7 #include<sys/socket.h> 8 9 void Usage(char *proc) 10 { 11 printf("Usage:%s [remoteip] [remoteport]\n",proc); 12 } 13 int main(int argc,char* argv[]) 14 { 15 if(argc!=3) 16 { 17 Usage(argv[0]); 18 exit(1); 19 } 20 int sock=socket(AF_INET,SOCK_DGRAM,0); 21 if(sock < 0) 22 { 23 perror("socket");
24 exit(1);
25 }
26 int _port=atoi(argv[2]);
27 char* _ip=argv[1];
28 struct sockaddr_in remote;
29 remote.sin_family=AF_INET;
30 remote.sin_port=htons(_port);
31 remote.sin_addr.s_addr=inet_addr(_ip);
32 socklen_t len=sizeof(remote);
33 int done=0;
34 char buf[1024];
35 while(!done)
36 {
37 memset(buf,'\0',sizeof(buf));
38 printf("please input:");
39 fflush(stdout);
40 ssize_t _size=read(0,buf,sizeof(buf)-1);
41 if(_size < 0)
42 {
43 perror("read");
44 return 2;
45 }
46 sendto(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&remote,len);
47 }
48 return 0;
49 }
運行結果:
端口號分配:(端口號即進程標識符)
TCP/IP的運輸層使用一個16位的端口號來標識一個端口,端口號只具有本地意義,只是爲了標誌本計算機應用層的各個進程在和運輸層交互時的層間接口,在因特網的不同計算機,相同的端口號是沒有關聯的。
服務器一般都是通過知名端口號來識別的。例如,對於TCP/IP實現來說,每個FTP服務器的TCP端口號都是21,每個Telnet服務器的TCP端口號都是23,每個TFTP(普通文件傳輸協議)服務器的UDP端口號都是69。
1).服務器端使用的端口號:
(1):熟知端口號爲0~1023,IANA把這些端口號指派給了TCP/IP最重要的應用程序,讓所有用戶都可以知道。
(2).登記端口號:爲1024~49151,是爲沒有熟知端口號的應用程序使用的,使用這類端口號必須在IANA按照規定登記,以防重複。
2).客戶端使用的端口號:49152~65535,因此類端口號僅在客戶進程進行時才動態選擇,可稱之爲短暫端口號,當服務器進程收到客戶進程的報文時,就知道了客戶進程使用的端口號,因此可將數據發送給客戶進程,通信結束該客戶端口號不存在,可以提供給其他客戶進程使用。
Internet擴展服務與UNIX特定服務之間的一個差別就是telnet和rlogin,它們二者都允許通過計算機網絡登錄到其他主機上。telnet是採用端口號爲23的TCP/IP標準,且幾乎可以在所有操作系統上進行實現。相反,rlogin最開始時只是爲UNIX系統設計的(儘管許多非UNIX系統現在也提供該服務)。客戶端口號又稱做臨時端口號(即存在時間很短暫),這是因爲它通常只是在用戶運行該客戶程序時才存在,而服務器則只要主機開着,其服務就運行。
大多數TCP/IP實現給臨時端口分配1 024~5 000之間的端口號。大於5 000的端口號是爲其他服務器預留的(Internet上並不常用的服務)。大多數Linux系統的文件/etc/services都包含了人們熟知的端口號。