tc_socket.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /**
  2. * Tencent is pleased to support the open source community by making Tars available.
  3. *
  4. * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  7. * in compliance with the License. You may obtain a copy of the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. */
  16. #ifndef __TC_SOCKET_H
  17. #define __TC_SOCKET_H
  18. #include "util/tc_platform.h"
  19. #if TARGET_PLATFORM_LINUX||TARGET_PLATFORM_IOS
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <sys/un.h>
  24. typedef int SOCKET_TYPE;
  25. typedef socklen_t SOCKET_LEN_TYPE;
  26. #else
  27. #include <winsock2.h>
  28. #include <windows.h>
  29. #include <in6addr.h>
  30. #include <WS2tcpip.h>
  31. #pragma comment(lib, "ws2_32.lib")
  32. typedef SOCKET SOCKET_TYPE;
  33. typedef int SOCKET_LEN_TYPE;
  34. #endif
  35. #include <vector>
  36. #include <string>
  37. #include "util/tc_ex.h"
  38. #include "util/tc_common.h"
  39. using namespace std;
  40. namespace tars
  41. {
  42. /////////////////////////////////////////////////
  43. /**
  44. * @file tc_socket.h
  45. * @brief socket封装类.
  46. *
  47. */
  48. /////////////////////////////////////////////////
  49. /**
  50. * @brief socket异常类
  51. */
  52. struct TC_Socket_Exception : public TC_Exception
  53. {
  54. TC_Socket_Exception(const string &buffer) : TC_Exception(buffer){};
  55. TC_Socket_Exception(const string &buffer, int err) : TC_Exception(buffer, err){};
  56. ~TC_Socket_Exception() throw() {};
  57. };
  58. /**
  59. * @brief 建立链接异常
  60. */
  61. struct TC_SocketConnect_Exception : public TC_Socket_Exception
  62. {
  63. TC_SocketConnect_Exception(const string &buffer) : TC_Socket_Exception(buffer){};
  64. TC_SocketConnect_Exception(const string &buffer, int err) : TC_Socket_Exception(buffer, err){};
  65. ~TC_SocketConnect_Exception() throw() {};
  66. };
  67. #if TARGET_PLATFORM_LINUX || TARGET_PLATFORM_IOS
  68. #define INVALID_SOCKET -1
  69. #endif
  70. /**
  71. * @brief Socket类, 封装了socket的基本方法
  72. */
  73. class TC_Socket
  74. {
  75. public:
  76. /**
  77. * @brief 构造函数
  78. */
  79. TC_Socket();
  80. /**
  81. * @brief 析够
  82. */
  83. virtual ~TC_Socket();
  84. /**
  85. * @brief 初始化.
  86. *
  87. * @param fd socket句柄
  88. * @param bOwner 是否拥有socket
  89. * @param iDomain sokect协议族,缺省为AF_INET,代表TCP/IP协议族
  90. */
  91. void init(int fd, bool bOwner, int iDomain = AF_INET);
  92. /**
  93. * @brief 设置是否拥有该fd.
  94. *
  95. * @param bOwner ture表示拥有,否则设置为false
  96. */
  97. void setOwner(bool bOwner) { _bOwner = bOwner; }
  98. /**
  99. * @brief 置设套接字类型
  100. *
  101. * @param iDomain 要设置的套接字的类型
  102. * AF_INET:TCP/IP协议族
  103. * AF_LOCAL:
  104. */
  105. void setDomain(int iDomain) { _iDomain = iDomain; }
  106. /**
  107. * @brief 生成socket, 如果已经存在以前的socket, 则释放掉,
  108. * 生成新的.
  109. *
  110. * @param iDomain socket方式SOCK_STREAM|SOCK_DGRAM
  111. * @param iSocketType socket类型,缺省AF_INET,TCP/IP族
  112. * @throws TC_Socket_Exception
  113. * @return
  114. */
  115. void createSocket(int iSocketType = SOCK_STREAM, int iDomain = AF_INET);
  116. /**
  117. * @brief 获取socket句柄.
  118. *
  119. * @return socket句柄
  120. */
  121. SOCKET_TYPE getfd() const { return _sock; }
  122. /**
  123. * @brief socket是否有效.
  124. *
  125. * @return true标识有效,否则返回false
  126. */
  127. bool isValid() const { return _sock != INVALID_SOCKET; }
  128. /**
  129. * @brief 关闭socket.
  130. *
  131. * @return void
  132. */
  133. void close();
  134. /**
  135. * @brief 获取对点的ip和端口,对AF_INET的socket有效.
  136. *
  137. * @param sPeerAddress 对点的ip地址
  138. * @param iPeerPort 对点的端口地址
  139. * @throws TC_Socket_Exception
  140. * @return
  141. */
  142. void getPeerName(string &sPeerAddress, uint16_t &iPeerPort) const;
  143. #if TARGET_PLATFORM_LINUX||TARGET_PLATFORM_IOS
  144. /**
  145. * @brief 获取对点的ip和端口,对AF_LOCAL的socket有效.
  146. *
  147. * @param sPathName 文件路径
  148. * @throws TC_Socket_Exception
  149. * @return
  150. */
  151. void getPeerName(string &sPathName) const;
  152. /**
  153. * @brief 获取socket文件路径,对AF_LOCAL的socket有效.
  154. *
  155. * @param sPathName
  156. * @param TC_Socket_Exception
  157. */
  158. void getSockName(string &sPathName) const;
  159. /**
  160. * @brief 绑定域套接字,对AF_LOCAL的socket有效.
  161. *
  162. * @param sPathName
  163. */
  164. void bind(const char *sPathName);
  165. /**
  166. * @brief 连接本地套接字,对AF_LOCAL的socket有效(同步连接).
  167. *
  168. * @param sPathName
  169. * @throws TC_Socket_Exception
  170. */
  171. void connect(const char *sPathName);
  172. /**
  173. * @brief 发起连接,连接失败的状态不通过异常返回,
  174. * 通过connect的返回值,在异步连接的时候需要
  175. * @param sPathName
  176. * @throws TC_Socket_Exception:其他错误还是通过异常返回(例如),例如地址错误
  177. * @return int
  178. */
  179. int connectNoThrow(const char *sPathName);
  180. #endif
  181. /**
  182. * @brief 获取自己的ip和端口,对AF_INET的socket有效.
  183. *
  184. * @param sSockAddress ip地址
  185. * @param iSockPort 端口地址
  186. * @throws TC_Socket_Exception
  187. * @return
  188. */
  189. void getSockName(string &sSockAddress, uint16_t &iSockPort) const;
  190. /**
  191. * @brief 修改socket选项.
  192. *
  193. * @param opt 选项名称
  194. * @param pvOptVal 选项值指针
  195. * @param optLen pvOptVal对应的长度
  196. * @param level socket操作层次, 默认是socket层
  197. * @return int
  198. */
  199. int setSockOpt(int opt, const void *pvOptVal, SOCKET_LEN_TYPE optLen, int level = SOL_SOCKET);
  200. /**
  201. * @brief 获取socket选项值.
  202. *
  203. * @param opt 选项名称
  204. * @param pvOptVal 输出, 选项值指针
  205. * @param optLen 输入pvOptVal指向的缓存的长度
  206. * @param level socket操作层次, 默认是socket层
  207. * @return socket选项值
  208. */
  209. int getSockOpt(int opt, void *pvOptVal, SOCKET_LEN_TYPE &optLen, int level = SOL_SOCKET) const;
  210. /**
  211. * @brief accept.
  212. *
  213. * @param tcSock 客户端socket结构
  214. * @param pstSockAddr 客户端地址
  215. * @param iSockLen pstSockAddr长度
  216. * @return int : > 0 ,客户端socket; <0, 出错
  217. */
  218. SOCKET_TYPE accept(TC_Socket &tcSock, struct sockaddr *pstSockAddr, SOCKET_LEN_TYPE &iSockLen);
  219. /**
  220. * @brief 绑定,对AF_INET的socket有效.
  221. *
  222. * @param port 端口
  223. * @param sServerAddr 服务器地址
  224. * @throws TC_Socket_Exception
  225. * @return
  226. */
  227. void bind(const string &sServerAddr, int port);
  228. /**
  229. * @brief 连接其他服务,对AF_INET的socket有效(同步连接).
  230. *
  231. * @param sServerAddr ip地址
  232. * @param port 端口
  233. * @throws TC_Socket_Exception
  234. * @return
  235. */
  236. void connect(const string &sServerAddr, uint16_t port);
  237. /**
  238. * @brief 发起连接,连接失败的状态不通过异常返回,
  239. * 通过connect的返回值,在异步连接的时候需要
  240. * @param sServerAddr ip地址
  241. * @param port 端口
  242. * @throws TC_Socket_Exception:
  243. * 其他错误还是通过异常返回(例如),例如地址错误
  244. * @return int
  245. */
  246. int connectNoThrow(const string &sServerAddr, uint16_t port);
  247. /**
  248. * @brief 发起连接,连接失败的状态不通过异常返回,
  249. * 通过connect的返回值,在异步连接的时候需要
  250. * @param addr socket直接可用的地址
  251. * @throws TC_Socket_Exception
  252. * 其他错误还是通过异常返回(例如),例如地址错误
  253. * @return int
  254. */
  255. int connectNoThrow(const struct sockaddr* addr);
  256. /**
  257. * @brief 在socket上监听.
  258. *
  259. * @param connBackLog 连接队列个数
  260. * @throws TC_Socket_Exception
  261. */
  262. void listen(int connBackLog);
  263. /**
  264. * @brief 绑定.
  265. *
  266. * @param pstBindAddr 需要绑定的地址
  267. * @param iAddrLen pstBindAddr指向的结构的长度
  268. * @throws TC_Socket_Exception
  269. * @return
  270. */
  271. void bind(const struct sockaddr *pstBindAddr, SOCKET_LEN_TYPE iAddrLen);
  272. /**
  273. * @brief 接收数据(一般用于tcp).
  274. *
  275. * @param pvBuf 接收buffer
  276. * @param iLen buffer长度
  277. * @param iFlag 标示
  278. * @return int 接收的数据长度
  279. */
  280. int recv(void *pvBuf, size_t iLen, int iFlag = 0);
  281. /**
  282. * @brief 发送数据(一般用于tcp).
  283. *
  284. * @param pvBuf 发送buffer
  285. * @param iLen buffer长度
  286. * @param iFlag 标示
  287. * @return int 发送了的数据长度
  288. */
  289. int send(const void *pvBuf, size_t iLen, int iFlag = 0);
  290. /**
  291. * @brief 接收数据(一般用于udp).
  292. *
  293. * @param pvBuf 发送buffer
  294. * @param iLen buffer长度
  295. * @param sFromAddr 输出, 服务端ip地址
  296. * @param iFromPort 输出, 服务端端口
  297. * @param iFlag 标示
  298. * @return int 接收了的数据长度
  299. */
  300. int recvfrom(void *pvBuf, size_t iLen, string &sFromAddr, uint16_t &iFromPort, int iFlags = 0);
  301. /**
  302. * @brief 接收数据(一般用于udp).
  303. *
  304. * @param pvBuf 发送buffer
  305. * @param iLen buffer长度
  306. * @param pstFromAddr 地址
  307. * @param iFromLen 输出, pstFromAddr长度
  308. * @param iFlag 标示
  309. * @return int 接收了的数据长度
  310. */
  311. int recvfrom(void *pvBuf, size_t iLen, struct sockaddr *pstFromAddr, SOCKET_LEN_TYPE &iFromLen, int iFlags = 0);
  312. /**
  313. * @brief 发送数据(一般用于udp).
  314. *
  315. * @param pvBuf 发送buffer
  316. * @param iLen buffer长度
  317. * @param sToAddr 服务端ip地址, 如果sToAddr为空, 则udp广播
  318. * @param iToPort 服务端端口
  319. * @param iFlag 标示
  320. * @return int : >0 发送的数据长度 ;<=0, 出错
  321. */
  322. int sendto(const void *pvBuf, size_t iLen, const string &sToAddr, uint16_t iToPort, int iFlags = 0);
  323. /**
  324. * @brief 发送数据(一般用于udp).
  325. *
  326. * @param pvBuf 发送buffer
  327. * @param iLen buffer长度
  328. * @param pstToAddr 服务端地址
  329. * @param iToLen pstToAddr长度
  330. * @param iFlag 标示
  331. * @return int : >0 发送的数据长度 ;<=0, 出错
  332. */
  333. int sendto(const void *pvBuf, size_t iLen, struct sockaddr *pstToAddr, SOCKET_LEN_TYPE iToLen, int iFlags = 0);
  334. /**
  335. * @brief 关闭.
  336. *
  337. * @param iHow 关闭方式:SHUT_RD|SHUT_WR|SHUT_RDWR
  338. * @throws TC_Socket_Exception
  339. * @return
  340. */
  341. void shutdown(int iHow);
  342. /**
  343. * @brief 设置socket方式 .
  344. *
  345. * @param bBlock true, 阻塞; false, 非阻塞
  346. * @throws TC_Socket_Exception
  347. * @return
  348. */
  349. void setblock(bool bBlock = false);
  350. /**
  351. * @brief 设置非closewait状态, 可以重用socket.
  352. *
  353. * @throws TC_Socket_Exception
  354. * @return void
  355. */
  356. void setNoCloseWait();
  357. /**
  358. * @brief 设置为closewait状态, 最常等待多久.
  359. *
  360. * @param delay 等待时间秒
  361. * @throws TC_Socket_Exception
  362. */
  363. void setCloseWait(int delay = 30);
  364. /**
  365. * @brief 设置closewait缺省状态,
  366. * close以后马上返回并尽量把数据发送出去
  367. * @throws TC_Socket_Exception
  368. */
  369. void setCloseWaitDefault();
  370. /**
  371. * @brief 设置nodelay(只有在打开keepalive才有效).
  372. *
  373. * @throws TC_Socket_Exception
  374. */
  375. void setTcpNoDelay();
  376. /**
  377. * @brief 设置keepalive.
  378. *
  379. * @throws TC_Socket_Exception
  380. * @return
  381. */
  382. void setKeepAlive();
  383. /**
  384. * @brief 获取recv buffer 大小.
  385. *
  386. * @throws TC_Socket_Exception
  387. * @return recv buffer 的大小
  388. */
  389. int getRecvBufferSize() const;
  390. /**
  391. * @brief 设置recv buffer 大小.
  392. * @param recv buffer 大小
  393. * @throws TC_Socket_Exception
  394. */
  395. void setRecvBufferSize(int sz);
  396. /**
  397. * @brief 获取发送buffer大小.
  398. * @param 发送buffer大小
  399. * @throws TC_Socket_Exception
  400. */
  401. int getSendBufferSize() const;
  402. /**
  403. * @brief 设置发送buffer大小.
  404. *
  405. * @throws TC_Socket_Exception
  406. * @param 发送buffer大小
  407. */
  408. void setSendBufferSize(int sz);
  409. /**
  410. * @brief 忽略SIGPIPE.
  411. */
  412. void ignoreSigPipe();
  413. /**
  414. * @brief 设置socket方式.
  415. *
  416. * @param fd 句柄
  417. * @param bBlock true, 阻塞; false, 非阻塞
  418. * @throws TC_Socket_Exception
  419. * @return
  420. */
  421. static void setblock(SOCKET_TYPE fd, bool bBlock);
  422. /**
  423. * @brief 获取本地所有ip.
  424. *
  425. * @throws TC_Socket_Exception
  426. * @return 本地所有ip
  427. */
  428. static vector<string> getLocalHosts(int domain = AF_INET);
  429. /**
  430. * @brief 生成管道,抛出异常时会关闭fd.
  431. * @param fds 句柄
  432. * @param bBlock true, 阻塞; false, 非阻塞
  433. * @throws TC_Socket_Exception
  434. */
  435. static void createPipe(int fds[2], bool bBlock);
  436. /**
  437. * @brief 解析地址, 从字符串(ip或域名), 解析到in_addr结构.
  438. *
  439. * @param sAddr 字符串
  440. * @param stAddr 地址
  441. * @throws TC_Socket_Exception
  442. * @return
  443. */
  444. static void parseAddr(const string &sAddr, struct in_addr &stAddr);
  445. /**
  446. * @brief 解析地址, 从字符串(ipv6或域名), 解析到in6_addr结构.
  447. *
  448. * @param sAddr 字符串
  449. * @param stAddr 地址
  450. * @throws TC_Socket_Exception
  451. * @return
  452. */
  453. static void parseAddr(const string &sAddr, struct in6_addr &stAddr);
  454. /**
  455. * @brief: Determine whether an address is ipv6 by including the character ':'
  456. * if address is a domain name, return default(not use now)
  457. * @param addr: ip address or domain name
  458. * @param def_value: if address is a domain name, return default(not use now)
  459. * @return: return true if addr is ipv6, false by ipv4, and default by domain name
  460. */
  461. static bool addressIsIPv6(const string& addr, bool def_value = false)
  462. {
  463. #define IPv6_ADDRESS_CHAR ':'
  464. return (addr.find(IPv6_ADDRESS_CHAR) != string::npos) ? true : false;
  465. #undef IPv6_ADDRESS_CHAR
  466. }
  467. /**
  468. * @brief 解析地址, 从字符串(ip或域名)端口, 解析到sockaddr_in结构.
  469. *
  470. * @param sAddr 字符串
  471. * @param stAddr 地址
  472. * @throws TC_Socket_Exception
  473. * @return
  474. */
  475. static void parseAddrWithPort(const string& host, int port, struct sockaddr_in& addr);
  476. static void parseAddrWithPort(const string& host, int port, struct sockaddr_in6& addr);
  477. /**
  478. * @brief 判断当前socket是否处于EAGAIN/WSAEWOULDBLOCK(异步send/recv函数返回值时判断)
  479. *
  480. * @return
  481. */
  482. static bool isPending();
  483. /**
  484. * @brief 判断当前socket是否处于EINPROGRESS/WSAEWOULDBLOC(异步connect返回值时判断)
  485. *
  486. * @return
  487. */
  488. static bool isInProgress();
  489. /**
  490. * @brief 关闭句柄
  491. *
  492. * @return
  493. */
  494. static void closeSocketNoThrow(int);
  495. #if 0
  496. /**
  497. * @brief no implementation.
  498. *
  499. */
  500. TC_Socket(const TC_Socket &tcSock);
  501. /**
  502. * @brief no implementation.
  503. */
  504. TC_Socket& operator=(const TC_Socket &tcSock);
  505. #endif
  506. protected:
  507. /**
  508. * @brief 连接其他服务.
  509. *
  510. * @param pstServerAddr 服务地址
  511. * @param serverLen pstServerAddr指向的结构的长度
  512. * @return int
  513. */
  514. int connect(const struct sockaddr *pstServerAddr, SOCKET_LEN_TYPE serverLen);
  515. /**
  516. * @brief 获取对点的地址.
  517. *
  518. * @param pstPeerAddr 地址指针
  519. * @param iPeerLen pstPeerAddr指向的结构长度
  520. * @throws TC_Socket_Exception
  521. * @return
  522. */
  523. void getPeerName(struct sockaddr *pstPeerAddr, SOCKET_LEN_TYPE &iPeerLen) const;
  524. /**
  525. * @brief 获取自己的的ip和端口.
  526. *
  527. * @param pstSockAddr 地址指针
  528. * @param iSockLen pstSockAddr
  529. * @throws TC_Socket_Exception
  530. * @return
  531. */
  532. void getSockName(struct sockaddr *pstSockAddr, SOCKET_LEN_TYPE &iSockLen) const;
  533. protected:
  534. /**
  535. * socket句柄
  536. */
  537. SOCKET_TYPE _sock;
  538. /**
  539. * 是否拥有socket
  540. */
  541. bool _bOwner;
  542. /**
  543. * socket类型
  544. */
  545. int _iDomain;
  546. };
  547. }
  548. #endif