freecplus是一個Linux系統下的C/C++開源框架,源代碼請前往C語言技術網(www.freecplus.net)下載。網絡
本文介紹的是freecplus框架的TCP/IP協議網絡通訊的函數和類。框架
函數和類的聲明文件是freecplus/_freecplus.h。異步
函數和類的定義文件是freecplus/_freecplus.cpp。socket
示例程序位於freecplus/demo目錄中。ide
編譯規則文件是freecplus/demo/makefile。函數
freecplus框架對socket通訊封裝以下:操作系統
CTcpClient類:socket通訊的客戶端類。.net
CTcpServer類:socket通訊的服務端類。計算機網絡
TcpRead函數:接收socket的對端發送過來的數據。3d
TcpWrite函數:向socket的對端發送數據。
Readn函數:從已經準備好的socket中讀取數據。
Writen函數:向已經準備好的socket中寫入數據。
在閱讀本文章以前,您必須熟悉TCP/IP協議和socket通訊,本文是介紹的是freecplus框架中網絡通訊的類和函數的用法,不會介紹網絡通訊的基礎知識。
freecplus框架的socket通訊報文格式以下:
報文長度+報文內容
報文長度爲4字節的整數,表示的是報文內容的長度,而不是整個TCP報文的長度,整個TCP報文的長度是報文內容的長度+4。
報文長度是4字節的整數,即int,是以二進制流的方式寫入socket,不是ascii碼。
採用CTcpClient類、CTcpServer類、TcpRead函數和TcpWrite函數進行socket通訊,能夠避免TCP報文粘包的問題。
socket通訊的客戶端封裝在CTcpClient類中。
類的聲明:
// socket通訊的客戶端類 class CTcpClient { public: int m_sockfd; // 客戶端的socket. char m_ip[21]; // 服務端的ip地址。 int m_port; // 與服務端通訊的端口。 bool m_state; // 與服務端的socket鏈接狀態。 bool m_btimeout; // 調用Read和Write方法時,失敗的緣由是不是超時:true-未超時,false-已超時。 int m_buflen; // 調用Read方法後,接收到的報文的大小,單位:字節。 CTcpClient(); // 構造函數。 // 向服務端發起鏈接請求。 // ip:服務端的ip地址。 // port:服務端監聽的端口。 // 返回值:true-成功;false-失敗。 bool ConnectToServer(const char *ip,const int port); // 接收服務端發送過來的數據。 // buffer:接收數據緩衝區的地址,數據的長度存放在m_buflen成員變量中。 // itimeout:等待數據的超時時間,單位:秒,缺省值是0-無限等待。 // 返回值:true-成功;false-失敗,失敗有兩種狀況:1)等待超時,成員變量m_btimeout的值被設置爲true;2)socket鏈接已不可用。 bool Read(char *buffer,const int itimeout=0); // 向服務端發送數據。 // buffer:待發送數據緩衝區的地址。 // ibuflen:待發送數據的大小,單位:字節,缺省值爲0,若是發送的是ascii字符串,ibuflen取0,若是是二進制流數據,ibuflen爲二進制數據塊的大小。 // 返回值:true-成功;false-失敗,若是失敗,表示socket鏈接已不可用。 bool Write(const char *buffer,const int ibuflen=0); // 斷開與服務端的鏈接 void Close(); ~CTcpClient(); // 析構函數自動關閉socket,釋放資源。 };
socket通訊的服務端封裝在CTcpServer類中。
類的聲明:
// socket通訊的服務端類 class CTcpServer { private: int m_socklen; // 結構體struct sockaddr_in的大小。 struct sockaddr_in m_clientaddr; // 客戶端的地址信息。 struct sockaddr_in m_servaddr; // 服務端的地址信息。 public: int m_listenfd; // 服務端用於監聽的socket。 int m_connfd; // 客戶端鏈接上來的socket。 bool m_btimeout; // 調用Read和Write方法時,失敗的緣由是不是超時:true-未超時,false-已超時。 int m_buflen; // 調用Read方法後,接收到的報文的大小,單位:字節。 CTcpServer(); // 構造函數。 // 服務端初始化。 // port:指定服務端用於監聽的端口。 // 返回值:true-成功;false-失敗,通常狀況下,只要port設置正確,沒有被佔用,初始化都會成功。 bool InitServer(const unsigned int port); // 阻塞等待客戶端的鏈接請求。 // 返回值:true-有新的客戶端已鏈接上來,false-失敗,Accept被中斷,若是Accept失敗,能夠從新Accept。 bool Accept(); // 獲取客戶端的ip地址。 // 返回值:客戶端的ip地址,如"192.168.1.100"。 char *GetIP(); // 接收客戶端發送過來的數據。 // buffer:接收數據緩衝區的地址,數據的長度存放在m_buflen成員變量中。 // itimeout:等待數據的超時時間,單位:秒,缺省值是0-無限等待。 // 返回值:true-成功;false-失敗,失敗有兩種狀況:1)等待超時,成員變量m_btimeout的值被設置爲true;2)socket鏈接已不可用。 bool Read(char *buffer,const int itimeout); // 向客戶端發送數據。 // buffer:待發送數據緩衝區的地址。 // ibuflen:待發送數據的大小,單位:字節,缺省值爲0,若是發送的是ascii字符串,ibuflen取0,若是是二進制流數據,ibuflen爲二進制數據塊的大小。 // 返回值:true-成功;false-失敗,若是失敗,表示socket鏈接已不可用。 bool Write(const char *buffer,const int ibuflen=0); // 關閉監聽的socket,即m_listenfd,經常使用於多進程服務程序的子進程代碼中。 void CloseListen(); // 關閉客戶端的socket,即m_connfd,經常使用於多進程服務程序的父進程代碼中。 void CloseClient(); ~CTcpServer(); // 析構函數自動關閉socket,釋放資源。 };
示例(demo47.cpp)
/* * 程序名:demo47.cpp,此程序演示採用freecplus框架的CTcpClient類實現socket通訊的客戶端。 * 做者:C語言技術網(www.freecplus.net) 日期:20190525 */ #include "../_freecplus.h" int main(int argc,char *argv[]) { CTcpClient TcpClient; // 建立客戶端的對象。 if (TcpClient.ConnectToServer("172.16.0.15",5858)==false) // 向服務端發起鏈接請求。 { printf("TcpClient.ConnectToServer(\"172.16.0.15\",5858) failed.\n"); return -1; } char strbuffer[1024]; // 存放數據的緩衝區。 for (int ii=0;ii<5;ii++) // 利用循環,與服務端進行5次交互。 { memset(strbuffer,0,sizeof(strbuffer)); snprintf(strbuffer,50,"這是第%d個超級女生,編號%03d。",ii+1,ii+1); printf("發送:%s\n",strbuffer); if (TcpClient.Write(strbuffer)==false) break; // 向服務端發送請求報文。 memset(strbuffer,0,sizeof(strbuffer)); if (TcpClient.Read(strbuffer,20)==false) break; // 接收服務端的迴應報文。 printf("接收:%s\n",strbuffer); sleep(1); } // 程序直接退出,析構函數會釋放資源。 }
示例(demo48.cpp)
/* * 程序名:demo48.cpp,此程序演示採用freecplus框架的CTcpServer類實現socket通訊的服務端。 * 做者:C語言技術網(www.freecplus.net) 日期:20190525 */ #include "../_freecplus.h" int main(int argc,char *argv[]) { CTcpServer TcpServer; // 建立服務端對象。 if (TcpServer.InitServer(5858)==false) // 初始化TcpServer的通訊端口。 { printf("TcpServer.InitServer(5858) failed.\n"); return -1; } if (TcpServer.Accept()==false) // 等待客戶端鏈接。 { printf("TcpServer.Accept() failed.\n"); return -1; } printf("客戶端(%s)已鏈接。\n",TcpServer.GetIP()); char strbuffer[1024]; // 存放數據的緩衝區。 while (true) { memset(strbuffer,0,sizeof(strbuffer)); if (TcpServer.Read(strbuffer,300)==false) break; // 接收客戶端發過來的請求報文。 printf("接收:%s\n",strbuffer); strcat(strbuffer,"ok"); // 在客戶端的報文後加上"ok"。 printf("發送:%s\n",strbuffer); if (TcpServer.Write(strbuffer)==false) break; // 向客戶端迴應報文。 } printf("客戶端已斷開。\n"); // 程序直接退出,析構函數會釋放資源。 }
我但願您已經學過計算機網絡的基礎知識,在運行示例程序以前,請確保您的Linux操做系統已開通防火牆。
在demo47.cpp和demo48.cpp程序中,服務端的ip地址和通訊端口是寫死在程序中的,請根據您的實際狀況修改它們,而後從新編譯。
先啓動demo48,而後啓動demo47。
demo47的運行效果以下:
demo48的運行效果以下:
採用CTcpClient和CTcpServer類實現socket通訊功能很是方便,可是在實際開發中,某些場景中不能只依賴這兩個類,例如多程線和異步通訊等場景,還必須結合如下將要介紹的幾個函數一塊兒使用。
接收socket的對端發送過來的數據。
函數的聲明:
bool TcpRead(const int sockfd,char *buffer,int *ibuflen,const int itimeout=0);
參數說明:
sockfd:可用的socket鏈接。
buffer:接收數據緩衝區的地址。
ibuflen:本次成功接收數據的字節數。
itimeout:接收等待超時的時間,單位:秒,缺省值是0-無限等待。
返回值:true-成功;false-失敗,失敗有兩種狀況:1)等待超時;2)socket鏈接已不可用。
在CTcpClient和CTcpServer類的Read方法中調用了TcpRead函數。
向socket的對端發送數據。
函數的聲明:
bool TcpWrite(const int sockfd,const char *buffer,const int ibuflen=0);
參數說明:
sockfd:可用的socket鏈接。
buffer:待發送數據緩衝區的地址。
ibuflen:待發送數據的字節數,若是發送的是ascii字符串,ibuflen取0,若是是二進制流數據,ibuflen爲二進制數據塊的大小。
返回值:true-成功;false-失敗,若是失敗,表示socket鏈接已不可用。
在CTcpClient和CTcpServer類的Write方法中調用了TcpRead函數。
從已經準備好的socket中讀取數據。
函數的聲明:
bool Readn(const int sockfd,char *buffer,const size_t n);
sockfd:已經準備好的socket鏈接。
buffer:接收數據緩衝區的地址。
n:本次接收數據的字節數。
返回值:成功接收到n字節的數據後返回true,socket鏈接不可用返回false。
注意:
1)sockfd是已經準備好的socket鏈接,那什麼是已經準備好的socket?在這個socket上,已經或立刻有n字節的數據必定會到達。
2)成功接收到n字節的數據後返回true,若是沒有n字節的數據怎麼辦?不會,在1)中已經說明了,必定會有n字節的數據會到達。
3)若是數據大於n字節怎麼辦?Readn只讀取n個字節的數據,其它的數據屬於其它的報文。
4)socket的對端是採用Writen方法寫入的數據。
在TcpRead函數中,調用了Readn函數。
向已經準備好的socket中寫入數據。
函數的聲明:
bool Writen(const int sockfd,const char *buffer,const size_t n);
sockfd:已經準備好的socket鏈接。
buffer:待發送數據緩衝區的地址。
n:待發送數據的字節數。
返回值:成功發送完n字節的數據後返回true,socket鏈接不可用返回false。
在TcpWrite函數中,調用了Writen函數。
C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道
若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!