Linux下Socket的簡單使用及最簡化封裝

來源:互聯網
上載者:User
Linux下Socket的簡單使用及最簡化封裝

/*
* 檔案功能: linux 下通訊端簡化操作函數
* 檔案名稱: linux_socket.h
* 建立時間: 2007 年 07 月 19 號
* 建立作者: wlzqi
* 使用語言: C 或 C++ 語言
* 使用環境: Linux + Windows
* 函數要求: 
*    + 函數相對比較底層
*    + 只使用系統API和C庫,不能使用任何第三方庫
*    + 不可以用全域變數
*    + 使用比較頻繁
*    + 具有模組化(函數不要嵌套)
*    +   要有足夠強壯性和高效
*    +   要經過一定強度的本地測試
*    + 盡量不使用動態分配記憶體(特殊情況可謹慎添加)
*    + 所有變數必須位元組對齊
* 代碼要求:
*    + 盡量減少臨時變數
*    + 演算法要精鍊
*    + 臨時變數名要使用英文或英文縮寫或英文片語單詞首字母,並且英文要準確(不要超過12個字母)
*    + 函數名要求將函數功能描述清楚,單詞之間要用 _ 串連。例如:analyze_string 分解字串、
*     execute_sql 執行SQL語句、get_database_field_name 得到資料庫欄位名稱.....等
*    + 所有函數均使用小寫字母拼字
*    + 符號 ,和; 後要有一空格、符號 & * 要緊挨右邊的變數、符號++ 要緊挨左邊的變數、所有運算子
*     兩邊都要留有空格
*    + if 和 for 、where 等要和緊挨的 '(' 符號間留有一空格
*    + 合理運用空行使代碼清晰易讀
* 注釋風格:
*    + 注釋要得當風格要統一
*    + 注釋只能在代碼之上(只能使用/**/)和同行(可以使用//和/**/)兩種風格
*    + 如果注釋和代碼同行,則要求必須空出兩個 Tab 鍵
*    + 注釋內容和注釋符之間要有一空格
*    + 如果注釋要分行寫則要求具有以下樣子
*     /* 
*         * 注釋內容
*         * 注釋內容
*         * */
*    + 函數功能注釋必須有:函數說明、參數說明、返回說明、注意事項、使用舉例
* 注意事項:
*    + 如遇本檔案中的函數與系統函數功能相同時,因優先考慮使用本檔案中的函數
*    + '必須'保證編譯時間不出現警告資訊
*   + 預設情況下,給一個已經中斷連線(非法斷開)的地址發送資料程式會退出,所以建議不要使用預設的
*    預設設定。建議應用根據需要處理 SIGPIPE 訊號,至少不要用系統預設的處理方式處理這個訊號
*    ,系統預設的處理方式是退出進程,這樣你的應用就很難查處處理進程為什麼退出。
*    如果調用 signal(SIGPIPE, SIG_IGN); 那麼程式在對方已斷開的情況下發送資料就會返回 -1,errno 號為 EPIPE(32)
*    如果調用 signal(SIGPIPE, function_name); 那麼程式在對方已斷開的情況下發送資料首先會 SIGPIPE 響應函數,然後返回 -1,errno 號為 EPIPE(32)
*    如果在發送資料中對方斷開,那麼發送端會先返回已發送的資料位元組數,在下次再調用發送時返回 -1,errno 號為 ECONNRESET(104) 
*    建議使用 signal 處理訊號,避免進程莫名退出和描述符泄露和死串連
* 已加模組:
*    + socket_format_err   格式化 socket 錯誤資訊
*   + socket_format_herr 自訂格式化 socket 錯誤資訊
*    + socket_create     建立 Socket
*    + socket_connect    串連 Socket
*   + socket_bind      邦定本地連接埠
*   + socket_listen     監聽本地連接埠描述符
*   + socket_accept     接受 Socket 連線
*    + socket_send      發送資料包
*    + socket_recv      接收資料包
*    + socket_send_pack   打包發送資料包
*    + socket_recv_pack   接收打包的資料包
*    + close_socket     關閉通訊端
* */

#ifndef LINUX_SOCKET_H_
#define LINUX_SOCKET_H_

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/

/* 定義 SOCKET 變數 */
typedef int SOCKET;

#ifndef boolean
#define boolean
/* 定義布爾型變數 */
typedef enum boolean {false, true} bool;
#endif

#ifndef FALSE
#define FALSE   (0) 
#endif

#ifndef TRUE
#define TRUE (!FALSE)
#endif

/* 定義布爾型變數 */
#ifndef BOOLLEAN
#define BOOLLEAN
typedef int BOOL;
#endif

/* 定義NULL字元 */
#ifndef NULL
#define NULL 0
#endif

/*---------------------------------------------------------------------------*/
/* 函數功能: 格式化 socket 錯誤資訊
* 參數說明: 無
* 返回說明: 返回錯誤描述資訊文本
* 注意事項: 
* 使用舉例:

* */
char * socket_format_err()
{
return (char *)hstrerror(h_errno);
}

/*---------------------------------------------------------------------------*/
/* 函數功能: 自訂格式化 socket 錯誤資訊
* 參數說明: pszErr 要在系統錯誤資訊描述前添加的自己的文字
* 返回說明: 無
* 注意事項: 
* 使用舉例: socket_format_herr("Warning");
*     輸出 Warning: xxxx.....

* */
void socket_format_herr(const char * pszErr)
{
herror(pszErr);
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 建立 Socket
* 參數說明: nTimeR   接收逾時(秒),0表示不受限
*       nTimeS   發送逾時(秒),0表示不受限
* 返回說明: 返回-1表示失敗。否則返回被建立的socket
* 注意事項: 函數內使用了連接埠重新綁定
* 使用舉例: 1. socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 10, 10) TCP
*       2. socket_create(AF_INET, SOCK_DGRAM, IPPROTO_IP, 0, 0)     UDP 
* */
SOCKET socket_create(const int nAf, const int nType, const int nProtocol, const int nTimeS, const int nTimeR)
{
static SOCKET m_sock;

#ifndef WIN32
struct timeval tv;
#endif

m_sock = -1;
m_sock = socket(nAf, nType, nProtocol);
if (m_sock == -1) return -1;

#ifdef WIN32

nTimeS *= 1000;
nTimeR *= 1000;
/* 發送時限 */
if (setsockopt(m_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&nTimeS, sizeof(int)) < 0)
   return -1;
/* 接收時限 */
if (setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeR, sizeof(int)) < 0)
   return -1;
#else
tv.tv_usec = 0;
tv.tv_sec = nTimeS;
/* 發送時限 */
if (setsockopt(m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
   return -1;
tv.tv_sec = nTimeR;
/* 接收時限 */
if (setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
   return -1;
#endif

return m_sock;
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 串連 Socket
* 參數說明: socket   通訊端
*        pcszIp   IP
*        nPort    連接埠
* 返回說明: 返回 false 表示失敗。
* 注意事項: 
* 使用舉例: 1. SOCKET socke;
*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
* */
bool socket_connect(const SOCKET socket, const char * pcszIp, const unsigned nPort)
{
   struct sockaddr_in svraddr;

   svraddr.sin_family = AF_INET;
   svraddr.sin_addr.s_addr = inet_addr(pcszIp);
   svraddr.sin_port = htons(nPort);
   if (connect(socket, (struct sockaddr *)&svraddr, sizeof(svraddr)) == -1) return false;
   return true;
}
/*---------------------------------------------------------------------------*/
/* 函數功能:邦定本地連接埠到描述符
* 參數說明:nPort 需要邦定的本地連接埠
* 返回說明:返回 false 表示失敗。
* 注意事項:
* 使用舉例:
*     if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0)) == -1) {
*  
*       return false;
*      }
*     if (socket_bind(socke, 9000) == false) return false;
* */
bool socket_bind(const SOCKET socket, const unsigned nPort)
{
int nOpt = 1;
struct sockaddr_in svraddr;

svraddr.sin_family = AF_INET;
svraddr.sin_addr.s_addr = INADDR_ANY;
svraddr.sin_port = htons(nPort);

if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nOpt, sizeof(nOpt)) < 0) return false;
if (bind(socket, (struct sockaddr*)&svraddr, sizeof(svraddr)) == -1) return false;

return true;
}
/*---------------------------------------------------------------------------*/
/* 函數功能:監聽本地連接埠描述符
* 參數說明:nBacklog 佈建要求排隊的最大長度,常用量為 5
* 返回說明:返回 false 表示失敗。
* 注意事項:
* 使用舉例:
*     if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0)) == -1) {
*  
*       return false;
*      }
*     if (socket_bind(socke, 9000) == false) return false;
*     if (socket_listen(socke, 5) == false) return false;
* */
bool socket_listen(const SOCKET socket, const int nBacklog)
{
if (listen(socket, nBacklog) == -1) return false;
return true;
}
/*---------------------------------------------------------------------------*/
/* 函數功能:接受 Socket 連線 
* 參數說明:pszCliIp [OUT] 對方IP地址
* 返回說明:成功返回客戶 socket 描述符,否則返回 -1。
* 注意事項:
* 使用舉例:
*     SOCKET m_sock;
*     char szCliIP[16];
*     if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0)) == -1) {
*  
*       return false;
*      }
*     if (socket_bind(socke, 9000) == false) return false;
*     if (socket_listen(socke, 5) == false) return false;
*     memset(szCliIP, 0, 16);
*     m_sock = socket_accept(socke, szCliIP);
* */
SOCKET socket_accept(const SOCKET socket, char * pszCliIp)
{
static SOCKET m_sock;
struct sockaddr_in cliaddr;

socklen_t addrlen = sizeof(cliaddr);
m_sock = accept(socket, (struct sockaddr*)&cliaddr, &addrlen);
if (m_sock == -1) return -1;

if (pszCliIp != NULL) sprintf(pszCliIp, "%s", inet_ntoa(cliaddr.sin_addr));
return m_sock;
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 發送 Socket 包
* 參數說明: socket   通訊端
*        pszBuff   待發送緩衝區
*        nLen   待發送包長度
* 返回說明: 返回-1表示失敗。否則返回實際已發送的位元組數
* 注意事項: nFlags一般取 0
* 使用舉例: 1. SOCKET socke;
*      char szBuff[512];
*      memset(szBuff, 0, 512);
*
*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
*      // 拷貝待發送位元組到緩衝區
*      socket_send(socke, szBuff, strlen(szBuff), 0);
* */
int socket_send(const SOCKET socket, const char * pszBuff, const int nLen, const int nFlags)
{
int nBytes = 0;
int nCount = 0;

while (nCount < nLen) {
  
   nBytes = send(socket, pszBuff + nCount, nLen - nCount, nFlags);
   if (nBytes <= 0) {

    return -1;
   }
   nCount += nBytes;
}

return nCount;
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 接收 Socket 包
* 參數說明: socket   通訊端
*     pszBuff   待接收緩衝區
*     nLen   待接收包長度
* 返回說明: 返回-1表示失敗。否則返回實際接收的位元組數
* 注意事項: nFlags一般取 0
* 使用舉例: 1. SOCKET socke;
*      char szBuff[512];
*      memset(szBuff, 0, 512);

*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 10)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
*      // 拷貝待發送位元組到緩衝區
*      socket_send(socke, szBuff, strlen(szBuff), 0);
*      socket_recv(socke, szBuff, strlen(szBuff), 0);
* */
int socket_recv(const SOCKET socket, char * pszBuff, const int nLen, const int nFlags)
{
return recv(socket, pszBuff, nLen, nFlags);
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 打包發送 Socket 包
* 參數說明: socket   通訊端
*     pszBuff   待發送緩衝區
*     nLength_all 待發送包總長度
*     unPack_Size 一次發送的位元組數
* 返回說明: 返回-1表示失敗。否則返回實際發送的位元組數
* 注意事項: 
* 使用舉例: 1. SOCKET socke;
*      char szBuff[512];
*      memset(szBuff, 0, 512);

*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 10)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
*      // 拷貝待發送位元組到緩衝區
*      socket_send_pack(socke, szBuff, strlen(szBuff), 512);
* */
unsigned long socket_send_pack(const SOCKET socket, const char * pszBuff, const unsigned long nLength_all, const unsigned unPack_Size)
{
int nLength = 0;
   long nAddLengths = 0;
      
   while(nAddLengths < nLength_all) {
   
    if ((nLength = socket_send(socket, pszBuff + nAddLengths, unPack_Size, 0)) < 0) {
               
       break;
     }
     nAddLengths += nLength;
   }
   return nAddLengths;
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 接收打包 Socket 包
* 參數說明: socket   通訊端
*     pszBuff   待接收緩衝區
*     nLength_all 待接收包總長度
*     unPack_Size 一次接收的位元組數
* 返回說明: 返回-1表示失敗。否則返回實際接收的位元組數
* 注意事項: 
* 使用舉例: 1. SOCKET socke;
*      char szBuff[512];
*      memset(szBuff, 0, 512);

*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 10)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
*      // 拷貝待發送位元組到緩衝區
*      socket_send_pack(socke, szBuff, strlen(szBuff), 512);
*      socket_recv_pack(socke, szBuff, 2048, 512);
* */
int socket_recv_pack(const SOCKET socket, char *pszBuff, const unsigned long nLength_all, const unsigned unPack_Size)
{

int nLength = 0;
unsigned long nAddLengths;
nAddLengths = 0;

while (nAddLengths < nLength_all) {

   if ((nLength = socket_recv(socket, pszBuff + nAddLengths, unPack_Size, 0)) < 0) {
   
    break;
   }
   nAddLengths += nLength;
}
return nAddLengths;
}
/*---------------------------------------------------------------------------*/
/* 函數功能: 關閉 Socket
* 參數說明: socket   通訊端
* 返回說明: 返回false表示失敗。否則返回實際接收的位元組數
* 注意事項: 
* 使用舉例: 1. SOCKET socke;
*      char szBuff[512];
*      memset(szBuff, 0, 512);

*      if ((socke = socket_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, 10)) == -1) {
*  
*       return false;
*      }
*      if (socket_connect(socke, "192.168.12.111", 9000) == false) return false;
*      // 拷貝待發送位元組到緩衝區
*      socket_send_pack(socke, szBuff, strlen(szBuff), 512);
*      socket_recv_pack(socke, szBuff, 2048, 512);
*      socket_close(socke);
* */
bool socket_close(const SOCKET socket)
{
return close(socket) == 0 ? true : false;
}
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/

#endif /*LINUX_SOCKET_H_*/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.