TCP與UDP比較(轉載)

兩種不同的協議而已,UDP實現起來相對比TCP更加的簡單. 
TCP-有連接,所以握手過程會消耗資源,過程爲可靠連接,不會丟失數據,適合大數據量交換 UDP-非可靠連接,會丟包,沒有校驗,速度快,無須握手過程 
 
簡單點講UDP把需要發送的包往網絡上一扔就不管它了,主要用於一些突發的小數據包,比如OICQ;而TCP還要實現差錯控制、流量控制等,主要用於持續的數據流,比如HTTP、FTP等協議。 
 
目前在中國寬帶有線網上開展的一些業務,如視頻、諮詢、股票等(用computer接受,需要特殊硬件卡),用的幾乎全都是UDP協議,這是基於UCP的 單向特性;至於互聯網上,UDP協議相對TCP協議的應用就少得多,因爲TCP協議的雙向互動特性能滿足用戶的實時需求,而UDP則太過於被動,UDP協 議的突出之處是在它的強大的組播及廣播功能上,做到‘一呼百應’。 
技術上講,實現起來區別不大,tcp需要首先建立連接,而udp只要綁定端口發送就行,tcp如果建立連接以後,能夠保證傳送的數據包次序,而udp則不能保證數據包到達的先後次序,甚至會丟包,就這點而言,udp的客戶端所要做的接收工作要更復雜(如接收文件等)  
通常我們在說到網絡編程時默認是指TCP編程,即用前面提到的socket函數創建一個socket用於TCP通訊,函數參數我們通常填爲 SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0),這表示建立一個socket用於流式網絡通訊。 
通過查看socket的man手冊可以看到socket函數的第一個參數的值可以爲下面這些值:  
Name                              Purpose  

PF_UNIX, PF_LOCAL     Local communication  

PF_INET                         IPv4 Internet protocols  

PF_INET6                       IPv6 Internet protocols 

PF_IPX                           IPX - Novell protocols 

PF_NETLINK                  Kernel user interface device  

PF_X25                           ITU-T X.25 / ISO-8208 protocol  

PF_AX25                         Amateur radio AX.25 protocol 

PF_ATMPVC                    Access to raw ATM PVCs 

PF_APPLETALK             Appletalk  

PF_PACKET                    Low level packet interface   
 

第二個參數支持下列幾種值:  


SOCK_STREAM 
Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be sup‐ ported. 
 
SOCK_DGRAM 

Supports datagrams (connectionless, unreliable messages of a fixed maximum length). 


SOCK_SEQPACKET 
Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a con‐ 
sumer is required to read an entire packet with each read system call.  


SOCK_RAW 
Provides raw network protocol access.  


SOCK_RDM 
Provides a reliable datagram layer that does not guarantee ordering.  


SOCK_PACKET 
Obsolete and should not be used in new programs; see packet(7). 
  
從這裏可以看出,SOCK_STREAM這種的特點是面向連接的,即每次收發數據之前必須通過connect建立連接,也是雙向的,即任何一方都可以收發數據,協議本身提供了一些保障機制保證它是可靠的、有序的,即每個包按照發送的順序到達接收方。 


而SOCK_DGRAM這種是User Datagram Protocol協議的網絡通訊,它是無連接的,不可靠的,因爲通訊雙方發送數據後不知道對方是否已經收到數據,是否正常收到數據。任何一方建立一個 socket以後就可以用sendto發送數據,也可以用recvfrom接收數據。根本不關心對方是否存在,是否發送了數據。它的特點是通訊速度比較 快。大家都知道TCP是要經過三次握手的,而UDP沒有。 


基於上述不同,UDP和TCP編程步驟也有些不同,如下: 
 
/********************************************************************* *filename: UDP編程介紹 
*purpose: 通過比較UDP和TCP編程對二者編程步驟進行總結說明 *tidied by: zhoulifa([email protected]) 周立發(http://zhoulifa.bokee.com) Linux愛好者 Linux知識傳播者 SOHO族 開發者 最擅長C語言 *date time:2007-01-24 20:12:00 
*Note: 任何人可以任意複製代碼並運用這些文檔,當然包括你的商業用途 * 但請遵循GPL 
*Thanks to: Google.com 
*Hope:希望越來越多的人貢獻自己的力量,爲科學技術發展出力 
*********************************************************************/  
TCP編程的服務器端一般步驟是:  
1、創建一個socket,用函數socket(); 
2、設置socket屬性,用函數setsockopt(); * 可選 
3、綁定IP地址、端口等信息到socket上,用函數bind(); 

4、開啓監聽,用函數listen(); 
5、接收客戶端上來的連接,用函數accept(); 
6、收發數據,用函數send()和recv(),者read()和write(); 7、關閉網絡連接; 8、關閉監聽; 


TCP編程的客戶端一般步驟是:  

1、創建一個socket,用函數socket(); 
2、設置socket屬性,用函數setsockopt();* 可選 
3、綁定IP地址、端口等信息到socket上,用函數bind();* 可選 4、設置要連接的對方的IP地址和端口等屬性; 
5、連接服務器,用函數connect(); 
6、收發數據,用函數send()和recv(),或者read()和write(); 7、關閉網絡連接;  
  
與之對應的UDP編程步驟要簡單許多,分別如下:  
UDP編程的服務器端一般步驟是: 
1、創建一個socket,用函數socket(); 
2、設置socket屬性,用函數setsockopt();* 可選 
3、綁定IP地址、端口等信息到socket上,用函數bind(); 

4、循環接收數據,用函數recvfrom(); 5、關閉網絡連接; 
   
UDP編程的客戶端一般步驟是: 

1、創建一個socket,用函數socket(); 
2、設置socket屬性,用函數setsockopt();* 可選 
3、綁定IP地址、端口等信息到socket上,用函數bind();* 可選 

4、設置對方的IP地址和端口等屬性; 

5、發送數據,用函數sendto(); 6、關閉網絡連接;

代碼:

/*服務端程序UDPServer.c*/  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <stdio.h>  
#include <errno.h>  
#define SERVER_PORT    8888  
#define MAX_MSG_SIZE    1024
   
void udps_respon(int sockfd)  {  
        struct sockaddr_in addr;          
	int    addrlen,n;  
        char    msg[MAX_MSG_SIZE];           
        while(1)  
        {      /*等待數據請求*/  
                n=recvfrom(sockfd,msg,MAX_MSG_SIZE,0,  
                        (struct sockaddr*)&addr,&addrlen);                  
		msg[n]=0;  
                /*顯示服務器端已經收到了信息*/  
                fprintf(stdout,"I have received %s",msg);  /*數據回送*/                  
		sendto(sockfd,msg,n,0,(struct sockaddr*)&addr,addrlen);          
	}  
}
   
int main(void)  {  
        int sockfd;  
        struct sockaddr_in addr;           
        sockfd=socket(AF_INET,SOCK_DGRAM,0);          
	if(sockfd <0) {  
                fprintf(stderr,"Socket Error:%s\n",strerror(errno));                  
		exit(1);          
	}  
        bzero(&addr,sizeof(struct sockaddr_in));          
	addr.sin_family=AF_INET;
	addr.sin_addr.s_addr=htonl(INADDR_ANY);          
	addr.sin_port=htons(SERVER_PORT);  
        if(bind(sockfd,(struct sockaddr *)&ddr,sizeof(struct sockaddr_in)) <0) {
               	fprintf(stderr,"Bind Error:%s\n",strerror(errno));                  
		exit(1);          
	}
	udps_respon(sockfd);
	close(sockfd);  
}


/*客戶端程序UDPClient.c,使用方法UDPClient ServerIP ServerPort*/  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <errno.h>  
#include <stdio.h>  
#include <unistd.h>  
#define MAX_BUF_SIZE    1024   
void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len)  {  
        char buffer[MAX_BUF_SIZE];          
	int n;  
        while(1)         
        {        /*從鍵盤讀入,寫到服務端*/  
                fgets(buffer,MAX_BUF_SIZE,stdin);  
                sendto(sockfd,buffer,strlen(buffer),0,addr,len);                  
		bzero(buffer,MAX_BUF_SIZE); /*從網絡上讀,寫到屏幕上*/  
                n=recvfrom(sockfd,buffer,MAX_BUF_SIZE,0,NULL,NULL);                  
		buffer[n]=0;  
                fputs(buffer,stdout);          
	}  
}   
int main(int argc,char **argv)  {  
        int sockfd,port;  
        struct sockaddr_in addr;           
        if(argc!=3) {  
                fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]);                  
		exit(1);          
	}           
        if((port=atoi(argv[2])) <0) {  
                fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]);                  
		exit(1);          
	}           
        sockfd=socket(AF_INET,SOCK_DGRAM,0);          
	if(sockfd <0) {  
                fprintf(stderr,"Socket  Error:%s\n",strerror(errno));                  
		exit(1);          
	}       
        /*填充服務器端的資料*/  
        bzero(&addr,sizeof(struct sockaddr_in));          
	addr.sin_family=AF_INET;          
	addr.sin_port=htons(port);  
        if(inet_aton(argv[1],&addr.sin_addr) <0) {  
                fprintf(stderr,"Ip error:%s\n",strerror(errno));                  
		exit(1);         
	}
	udpc_requ(sockfd,&addr,sizeof(struct sockaddr_in));
	close(sockfd);  
}







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