TCP和UDP協(xié)議屬于傳輸層協(xié)議,其中TCP提供IP環(huán)境下的數(shù)據(jù)可靠傳輸叠荠,它提供的服務(wù)包括數(shù)據(jù)流傳送、可靠性竖共、有效流控蝙叛、全雙工操作和多路復(fù)用。通過面向連接公给、端到端和可靠的數(shù)據(jù)包發(fā)送借帘。通俗說,它是事先為所發(fā)送的數(shù)據(jù)開辟出連接好的通道淌铐,然后再進(jìn)行數(shù)據(jù)發(fā)送肺然;而UDP則不為IP提供可靠性、流控或差錯恢復(fù)功能腿准。一般來說际起,TCP對應(yīng)的是可靠性要求高的應(yīng)用,而UDP對應(yīng)的則是可靠性要求低吐葱、傳輸經(jīng)濟(jì)的應(yīng)用街望。TCP支持的應(yīng)用協(xié)議主要有:Telnet、FTP弟跑、SMTP等灾前;UDP支持的應(yīng)用層協(xié)議主要有:NFS(網(wǎng)絡(luò)文件系統(tǒng))、SNMP(簡單網(wǎng)絡(luò)管理協(xié)議)孟辑、DNS(主域名稱系統(tǒng))哎甲、TFTP(通用文件傳輸協(xié)議)等。
TCP/UDP的區(qū)別
作為運(yùn)輸層中兩個主要的協(xié)議饲嗽,TCP和UDP都能向應(yīng)用層提供通信服務(wù)炭玫,然而它們提供的服務(wù)差別還是很大的。
1.TCP協(xié)議是面向連接的貌虾。也就是說吞加,應(yīng)用程序在使用 TCP協(xié)議之前,必須先建立起一個 TCP連接尽狠,之后才能進(jìn)行通信活動衔憨。因此,使用 TCP協(xié)議通訊就好像是打電話晚唇,通話前先要撥號,然后等對端拿起電話盗似,建立好連接后才能開始通話哩陕,通話結(jié)束后將電話機(jī)扣上,此時相當(dāng)于斷開連接。
UDP協(xié)議是無連接的悍及。不需要建立和斷開連接闽瓢,發(fā)送端可以在任何時候自由地發(fā)送數(shù)據(jù),這就好像用手機(jī)發(fā)信息心赶,它不需要號碼是正確的扣讼,全憑發(fā)送端意愿進(jìn)行發(fā)送,結(jié)果是什么并不能保證缨叫。
2.UDP協(xié)議支持一對一椭符、一對多、多對一和多對多的交互通信耻姥。 而 TCP協(xié)議僅支持一對一的交互通信销钝。
3.UDP協(xié)議是面向報文的。發(fā)送方的 UDP對應(yīng)用程序交付下來的報文琐簇,再添加了首部信息之后就向下交付給 IP層蒸健。這就是說,應(yīng)用層交給 UDP多長的報文婉商,UDP會照原樣發(fā)送似忧,即一次發(fā)送一個報文≌芍龋可以看出盯捌,應(yīng)用程序必須控制報文的長度。TCP是面向癣籽,字節(jié)流的挽唉。
4.每一條TCP連接只能是點到點的;UDP支持一對一,一對多筷狼,多對一和多對多的交互通信
5.TCP首部開銷20字節(jié);UDP的首部開銷小瓶籽,只有8個字節(jié)
6.TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道
TCP,UDP編程區(qū)別
通常我們在說到網(wǎng)絡(luò)編程時默認(rèn)是指TCP編程埂材,即用前面提到的socket函數(shù)創(chuàng)建一個socket用于TCP通訊塑顺,函數(shù)參數(shù)我們通常填為SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0)俏险,這表示建立一個socket用于流式網(wǎng)絡(luò)通訊严拒。
SOCK_STREAM這種的特點是面向連接的,即每次收發(fā)數(shù)據(jù)之前必須通過connect建立連接竖独,也是雙向的裤唠,即任何一方都可以收發(fā)數(shù)據(jù),協(xié)議本身提供了一些保障機(jī)制保證它是可靠的莹痢、有序的种蘸,即每個包按照發(fā)送的順序到達(dá)接收方墓赴。
SOCK_DGRAM這種是User Datagram Protocol協(xié)議的網(wǎng)絡(luò)通訊,它是無連接的航瞭,不可靠的诫硕,因為通訊雙方發(fā)送數(shù)據(jù)后不知道對方是否已經(jīng)收到數(shù)據(jù),是否正常收到數(shù)據(jù)刊侯。任何一方建立一個socket以后就可以用sendto發(fā)送數(shù)據(jù)章办,也可以用recvfrom接收數(shù)據(jù)。根本不關(guān)心對方是否存在滨彻,是否發(fā)送了數(shù)據(jù)藕届。它的特點是通訊速度比較快。大家都知道TCP是要經(jīng)過三次握手的疮绷,而UDP沒有翰舌。
基于上述不同,UDP和TCP編程步驟也有些不同冬骚,如下:
TCP:
TCP編程的服務(wù)器端一般步驟是:
1椅贱、創(chuàng)建一個socket,用函數(shù)socket()只冻;
2庇麦、設(shè)置socket屬性,用函數(shù)setsockopt(); * 可選
3喜德、綁定IP地址山橄、端口等信息到socket上,用函數(shù)bind();
4舍悯、開啟監(jiān)聽航棱,用函數(shù)listen();
5萌衬、接收客戶端上來的連接饮醇,用函數(shù)accept();
6秕豫、收發(fā)數(shù)據(jù)朴艰,用函數(shù)send()和recv(),或者read()和write();
7混移、關(guān)閉網(wǎng)絡(luò)連接祠墅;
8、關(guān)閉監(jiān)聽歌径;
TCP編程的客戶端一般步驟是:
1毁嗦、創(chuàng)建一個socket,用函數(shù)socket()回铛;
2狗准、設(shè)置socket屬性芯急,用函數(shù)setsockopt();* 可選
3、綁定IP地址驶俊、端口等信息到socket上,用函數(shù)bind();* 可選
4免姿、設(shè)置要連接的對方的IP地址和端口等屬性饼酿;
5、連接服務(wù)器胚膊,用函數(shù)connect()故俐;
6、收發(fā)數(shù)據(jù)紊婉,用函數(shù)send()和recv()药版,或者read()和write();
7、關(guān)閉網(wǎng)絡(luò)連接喻犁;
UDP:
與之對應(yīng)的UDP編程步驟要簡單許多槽片,分別如下:
UDP編程的服務(wù)器端一般步驟是:
1、創(chuàng)建一個socket肢础,用函數(shù)socket()还栓;
2、設(shè)置socket屬性传轰,用函數(shù)setsockopt();* 可選
3剩盒、綁定IP地址、端口等信息到socket上慨蛙,用函數(shù)bind();
4辽聊、循環(huán)接收數(shù)據(jù),用函數(shù)recvfrom();
5期贫、關(guān)閉網(wǎng)絡(luò)連接跟匆;
UDP編程的客戶端一般步驟是:
1、創(chuàng)建一個socket唯灵,用函數(shù)socket()贾铝;
2、設(shè)置socket屬性埠帕,用函數(shù)setsockopt();* 可選
3垢揩、綁定IP地址、端口等信息到socket上敛瓷,用函數(shù)bind();* 可選
4叁巨、設(shè)置對方的IP地址和端口等屬性;
5、發(fā)送數(shù)據(jù)呐籽,用函數(shù)sendto();
6锋勺、關(guān)閉網(wǎng)絡(luò)連接蚀瘸;
操作函數(shù)
1、 socket:
創(chuàng)建socket 描述符
int socket(int domain, int type, int protocol);
domain=AF_INET庶橱,socket的類型贮勃,type=SOCK_STREAM 或SOCK_DGRAM,分別表示TCP連接和UDP連接;protocol=0苏章。
返回一個整型socket描述符寂嘉。
2.bind:
將socket描述符與你本機(jī)上的一個端口相關(guān)聯(lián)(僅用于服務(wù)器)
int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
Sockfd是一個socket描述符
my_addr是一個指向包含有本機(jī)IP地址及端口號等信息的sockaddr類型的指針;
addrlen=sizeof(struct sockaddr)。
返回:成功=0;失敗=-1枫绅,errno=錯誤號泉孩。
可以用下面的賦值自動獲得本機(jī)IP地址和隨機(jī)獲取一個沒有被占用的端口號:
my_addr.sin_port = 0; /* 系統(tǒng)隨機(jī)選擇一個未被使用的端口號 */
my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本機(jī)IP地址 */
3.Connect:
與遠(yuǎn)端服務(wù)器建立一個TCP連接 (用于客戶端)
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
Sockfd是目的服務(wù)器的sockt描述符
serv_addr是包含目的機(jī)IP地址和端口號的指針。
返回:成功=0;失敗=-1并淋,errno=錯誤號寓搬。
4、Listen:
監(jiān)聽是否有服務(wù)請求 县耽,用于bind()后
int listen(int sockfd句喷, int backlog);
Sockfd是Socket系統(tǒng)調(diào)用返回的socket 描述符;
backlog指定在請求隊列中允許的最大請求數(shù),缺省值為20兔毙。
返回:成功=0;失敗=-1脏嚷,errno=錯誤號。
5.accept:
接受來自客戶的請求
int accept(int sockfd, void *addr, int *addrlen);
sockfd是被監(jiān)聽的socket描述符瞒御,
addr 是指向sockaddr_in變量的指針父叙,存放客戶主機(jī)的信息 ;
addrten 指向值為sizeof(struct sockaddr_in)的整型指針變量。
返回:成功返回一個新的socket描述符肴裙,來供這個新連接來使用趾唱。 錯誤發(fā)生時返回一個-1并且設(shè)置相應(yīng)的errno值。
6.Send:
在連接(TCP)的socket方式下發(fā)送信息
int send(int sockfd, const void *msg, int len, int flags);
Sockfd是用來傳輸數(shù)據(jù)的socket描述符
msg是一個指向要發(fā)送數(shù)據(jù)的指針蜻懦。
Len是以字節(jié)為單位的數(shù)據(jù)的長度甜癞。
flags一般情況下置為0。
7.recv:
在連接(TCP)的socket方式下接收數(shù)據(jù)
int recv(int sockfd,void *buf,int len,unsigned int flags);
Sockfd是接受數(shù)據(jù)的socket描述符;
buf 是存放接收數(shù)據(jù)的緩沖區(qū);
len是緩沖的長度宛乃。
Flags也被置為0悠咱。
返回:實際上接收的字節(jié)數(shù),如果連接中止征炼,返回0,析既。出現(xiàn)錯誤時,返回-1并置相應(yīng)的errno值谆奥。
8.sendto:
在在無連接(UDP)的socket方式下發(fā)送數(shù)據(jù)
int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);
to表示目地機(jī)的IP地址和端口號信息
tolen=sizeof (struct sockaddr)眼坏。
返回:實際發(fā)送的數(shù)據(jù)字節(jié)長度或在出現(xiàn)發(fā)送錯誤時返回-1。
9.Recvfrom()
在無連接(UDP)的socket方式下接收數(shù)據(jù)
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);
from 保存源機(jī)的IP地址及端口號酸些。
fromlen=sizeof(struct sockaddr)宰译。
返回:實際存入from中的數(shù)據(jù)字節(jié)數(shù)檐蚜。當(dāng)出現(xiàn)錯誤時返回-1,并置相應(yīng)的errno沿侈。
10.close()
釋放socket闯第,停止任何數(shù)據(jù)操作
close(sockfd);
11.shutdown:
單向關(guān)閉連接
int shutdown(int sockfd,int how);
how可以設(shè)為下列值:
·0-------不允許繼續(xù)接收數(shù)據(jù)
·1-------不允許繼續(xù)發(fā)送數(shù)據(jù)
·2-------不允許繼續(xù)發(fā)送和接收數(shù)據(jù),均為允許則調(diào)用close ()
shutdown在操作成功時返回0缀拭,在出現(xiàn)錯誤時返回-1(并置相應(yīng)errno)乡括。
12. gethostbyname:
域名和IP地址的轉(zhuǎn)換
struct hostent *gethostbyname(const char *name);
13.inet_pton函數(shù):
將點分十進(jìn)制串轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序二進(jìn)制值,此函數(shù)對IPv4地址和IPv6地址都能處理智厌。
int inet_pton(int family,const char * strptr,void * addrptr);