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 devicePF_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第二個參數支持下列幾種值:
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);
}