【文章內(nèi)容簡介】
r的應(yīng)用程序,因?yàn)镕IN的接收意味著server的應(yīng)用進(jìn)程在相應(yīng)的連接上再也接收不到額外數(shù)據(jù);一段時(shí)間之后,server上接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用close關(guān)閉它的socket。這導(dǎo)致它的TCP也發(fā)送一個(gè)FIN N;接收到這個(gè)FIN的源發(fā)送端TCP對(duì)它進(jìn)行確認(rèn)。這樣每個(gè)方向上都有一個(gè)FIN和ACK。圖10 socket中發(fā)送的TCP四次握手釋放調(diào)通了TCP之后,我去嘗試UDP。其實(shí)這順序是反了的,因?yàn)閁DP貌似更簡單一些,可是因?yàn)門CP有現(xiàn)成的代碼,所以就先理解了TCP。之后去查UDP的資料,直觀上感覺除了創(chuàng)建socket()時(shí)定義的協(xié)議不同外,就是少了一些函數(shù),少用了一個(gè)socket。對(duì)于server來講,bind()之后,不用再listen和accept了,就是不用監(jiān)聽了,直接用這個(gè)socket來進(jìn)行數(shù)據(jù)傳輸就可以了。于是我就想當(dāng)然地覺得下面進(jìn)行網(wǎng)絡(luò)I/O的收發(fā)函數(shù)應(yīng)該是差不多的,就直接用了剛才在TCP里用的recv和send。對(duì)于client來講,我也是直接用的這兩個(gè)函數(shù)。然后怎么都傳不了數(shù)據(jù),實(shí)現(xiàn)不了通信。于是我仔細(xì)比較了幾個(gè)函數(shù)的參數(shù),發(fā)現(xiàn)recvfrom比recv多了2個(gè)參數(shù),后來理解了一下,這是因?yàn)門CP在accept時(shí)就為與之通信的每個(gè)進(jìn)程分配了一個(gè)socket用于數(shù)據(jù)傳輸,也就是說對(duì)于server的每個(gè)client都有一個(gè)專門的進(jìn)程與其進(jìn)行通信。而UDP沒有開另外的進(jìn)程,也就是沒有創(chuàng)建新的socket,所以server的多個(gè)client是共用這一個(gè)socket的,可以說是多路復(fù)用了。為了辨別多個(gè)client,server需要client的地址(ip+port)來接受和發(fā)送,于是就要用recvfrom多出來的2個(gè)參數(shù),即client的地址和地址長度。這也就同時(shí)解釋了為什么UDP只創(chuàng)建一個(gè)socket就夠了。對(duì)于UDP的client端來說,只需要在發(fā)送數(shù)據(jù)的時(shí)候用sendto來表明server的地址,在接收數(shù)據(jù)時(shí)就不需要的了,因?yàn)橹挥幸粋€(gè)server,不需要標(biāo)記了。因?yàn)槲沂窃谔摂M機(jī)上進(jìn)行的以上實(shí)驗(yàn),我就想利用主機(jī)和虛擬機(jī)之間的局域網(wǎng)來建立連接,進(jìn)行進(jìn)程通信。雖然操作系統(tǒng)不同,socket庫不同,但是只要使用了相同的協(xié)議(我選擇的是UDP)就可以進(jìn)行通信。于是我又去學(xué)習(xí)了Winsock的相關(guān)知識(shí),實(shí)現(xiàn)了不同系統(tǒng)間的通信。我覺得雖然Windows和Linux的socket使用總體上差不多,但是Winsock的一些準(zhǔn)備(我覺得比較冗余)復(fù)雜一點(diǎn)。 四、源代碼【UDP方案1】Server端源碼://udpService: include sys/ include sys/ include netinet/ include include include include include include include define PORT 7000 int main(void) { int sockfd,pktlen。 char buf[300],buf1[300]。 struct sockaddr_in server,client。sockfd=socket(AF_INET,SOCK_DGRAM,0)。 memset ((char *)amp。server, sizeof(server), 0)。 //將已開辟內(nèi)存空間 server = AF_INET。 = htons(PORT)。//端口號(hào) = INADDR_ANY。//設(shè)置網(wǎng)絡(luò)地址,INADDR_ANY表示機(jī)器的IP地址bind(sockfd,(struct sockaddr *)amp。server,sizeof(struct sockaddr_in))。 for (。) {/*recv接受client發(fā)送的數(shù)據(jù),recv函數(shù)僅僅是copy數(shù)據(jù),真正的接收數(shù)據(jù)是協(xié)議來完成的),第一個(gè)參數(shù)指定接收端套接字描述符;第二個(gè)參數(shù)指明一個(gè)緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù);第三個(gè)參數(shù)指明buf的長度recv函數(shù)返回其實(shí)際copy的字節(jié)數(shù)*/ int l=sizeof(struct sockaddr_in)。 pktlen = recvfrom (sockfd, buf, sizeof (buf), 0,(struct sockaddr_in *)amp。client,amp。l)。 if (pktlen == 0) break。 printf (Received line: %s\n, buf)。 printf (Enter a line: )。 fgets(buf1,300,stdin)。/*并不是send把ns的發(fā)送緩沖中的數(shù)據(jù)傳到連接的另一端的,而是協(xié)議傳的,send僅僅是把buf中的數(shù)據(jù)copy到ns的發(fā)送緩沖區(qū)的剩余空間里返回實(shí)際copy的字節(jié)數(shù)*/sendto (sockfd, buf1,sizeof(buf1), 0,(struct sockaddr_in*)amp。client,l)。}close(sockfd)。 }Client端源碼://udpClie