現(xiàn)在,我們通過(guò)accept()創(chuàng)建了新的socket,也就是我們類(lèi)中的數(shù)據(jù)成員communicationSock,現(xiàn)在,我們就可以通過(guò)這個(gè)socket進(jìn)行通訊了。

       TCP通訊模型

       在介紹函數(shù)之前,我們應(yīng)該了解一些事實(shí)。TCP的Server/Client模型類(lèi)似這樣:

       ServApp——ServSock——Internet——ClntSock——ClntApp

       當(dāng)然,我們這里的socket指的就是用于“通訊”的socket。TCP的server端至少有兩個(gè)socket,一個(gè)用于監(jiān)聽(tīng),一個(gè)用于通訊;TCP的server端可以只有一個(gè)socket,這個(gè)socket同時(shí)“插”在server的兩個(gè)socket上。當(dāng)然,插上listen socket的目的只是為了創(chuàng)建communication socket,創(chuàng)建完備后,listen是可以關(guān)閉的。但是,如果這樣,其他的client就無(wú)法再連接上server了。

       我們這個(gè)模型,是client的socket插在server的communication socket上的示意。這兩個(gè)socket,都擁有完整的本地地址信息以及遠(yuǎn)程計(jì)算機(jī)地址信息,所以,這兩個(gè)socket以及之間的網(wǎng)絡(luò)實(shí)際上形成了一條形式上“封閉”的管道。數(shù)據(jù)包只要從一端進(jìn)來(lái),就能知道出去的目的地,反之亦然。這正是TCP協(xié)議,數(shù)據(jù)流形式抽象化以及實(shí)現(xiàn)。因?yàn)椴辉傩枰该鳌俺鎏帯焙汀叭ハ颉保瑢?duì)這樣的socket(實(shí)際上是S/C上的socket對(duì))的操作,就如同對(duì)本地文件描述符的操作一樣。但是,盡管我們可以使用read()和write(),但是,為了完美的控制,我們最好使用recv()和send()。

       recv()和send()

C++代碼
  1. int send(int socket, const void* msg, unsigned int msgLength, int flags);  
  2. int recv(int socket, void* rcvBuffer, unsigned int bufferLength, int flags);  

       在Linux中的實(shí)現(xiàn)為:

C++代碼
  1. #include <sys/socket.h>  
  2.   
  3. /* Send N bytes of BUF to socket FD.  Returns the number sent or -1. 
  4.  
  5.    This function is a cancellation point and therefore not marked with 
  6.    __THROW.  */  
  7. extern ssize_t send (int __fd, __const void *__buf, size_t __n, int __flags);  
  8.   
  9. /* Read N bytes into BUF from socket FD. 
  10.    Returns the number read or -1 for errors. 
  11.  
  12.    This function is a cancellation point and therefore not marked with 
  13.    __THROW.  */  
  14. extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);  

       這兩個(gè)函數(shù)的第一個(gè)參數(shù)是用于“通訊”的socket,第二個(gè)參數(shù)是發(fā)送或者接收數(shù)據(jù)的起始點(diǎn)指針,第三個(gè)參數(shù)是數(shù)據(jù)長(zhǎng)度,第四個(gè)參數(shù)是控制符號(hào)(默認(rèn)屬性設(shè)置為0就可以了)。失敗時(shí)候傳回-1,否則傳回實(shí)際發(fā)送或者接收數(shù)據(jù)的大小,返回0往往意味著連接斷開(kāi)了。

       處理echo行為

C++代碼
  1. void TcpServer::handleEcho()  
  2. {  
  3.     const int BUFFERSIZE = 32;  
  4.     char buffer[BUFFERSIZE];  
  5.     int recvMsgSize;  
  6.     bool goon = true;  
  7.   
  8.     while ( goon == true ) {  
  9.         if ( (recvMsgSize = recv(communicationSock, buffer, BUFFERSIZE, 0)) < 0 ) {  
  10.             throw "recv() failed";  
  11.         } else if ( recvMsgSize == 0 ) {  
  12.             goon = false;  
  13.         } else {  
  14.             if ( send(communicationSock, buffer, recvMsgSize, 0) != recvMsgSize ) {  
  15.                 throw "send() failed";  
  16.             }  
  17.         }  
  18.     }  
  19.   
  20.     close(communicationSock);  
  21. }  

       本小節(jié)最后要講的函數(shù)是close(),它包含在<unistd.h>中

C++代碼
  1. #include <unistd.h>  
  2.   
  3. /* Close the file descriptor FD. 
  4.  
  5.    This function is a cancellation point and therefore not marked with 
  6.    __THROW.  */  
  7. extern int close (int __fd);  

       這個(gè)函數(shù)用于關(guān)閉一個(gè)文件描述符,自然,也就可以用于關(guān)閉socket。

       下一小節(jié)是完整的源代碼。默認(rèn)的監(jiān)聽(tīng)端口是5000。我們可以通過(guò)

       $telnet 127.0.0.1 5000

       驗(yàn)證在本機(jī)運(yùn)行的echo server程序。