• TCP 用setsockopt()设置等待时间,减少主动关闭方所处TIME_WAIT的时间


    目录

    1.背景 

    2.代码(new_tcp)


    1.背景 

    运行服务器及客户端:

    ./tcp_srv

    ./tcp_cli 192.168.164.128 20000

    关闭服务器端:---客户端变成了CLOSE_WAIT状态 ,此时服务端处于FIN_WAIT2状态

    关闭客户端:

     此时服务器虽然已经关闭,但处于TIME_WAIT状态,需等待一段时间才可重新启动。

    否则会出现:

     在此场景下,为了能尽快启动服务器,可设置TIME_WAIT等待时间,代码如下面所示。结果如图:

    启动服务器->启动客户端->关闭服务器->关闭客户端->重启服务器

     (虽然程序退出,但套接字资源并没有释放,它是在内核内部完成四次挥手的过程)

    2.代码(new_tcp)

    tcp_socket.hpp:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define MAX_LISTEN 5
    9. #define CHECK_RES(q) if((q)==false) { return -1;}
    10. class TcpSocket{
    11. private:
    12. int _sockfd;
    13. public:
    14. TcpSocket():_sockfd(-1){}
    15. void SetReuseAddr()
    16. {
    17. int opt = 1;
    18. setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(int));
    19. }
    20. //创建套接字
    21. bool Socket()
    22. {
    23. _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    24. if(_sockfd < 0)
    25. {
    26. perror("socket error");
    27. return false;
    28. }
    29. return true;
    30. }
    31. //绑定地址信息
    32. bool Bind(const std::string &ip,uint16_t port)
    33. {
    34. struct sockaddr_in addr;//先定义一个ipv4的地址结构
    35. addr.sin_family = AF_INET;
    36. addr.sin_port = htons(port);
    37. addr.sin_addr.s_addr = inet_addr(ip.c_str());
    38. socklen_t len = sizeof(struct sockaddr_in);
    39. int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
    40. if(ret<0)
    41. {
    42. perror("bind error");
    43. return false;
    44. }
    45. return true;
    46. }
    47. //向服务器发起连接
    48. bool Connect(const std::string &ip,uint16_t port)
    49. {
    50. struct sockaddr_in addr;
    51. addr.sin_family = AF_INET;
    52. addr.sin_port = htons(port);
    53. addr.sin_addr.s_addr = inet_addr(ip.c_str());
    54. socklen_t len = sizeof(struct sockaddr_in);
    55. int ret = connect(_sockfd,(struct sockaddr*)&addr,len);
    56. if(ret < 0)
    57. {
    58. perror("connect error");
    59. return false;
    60. }
    61. return true;
    62. }
    63. //服务器开始监听
    64. bool Listen(int backlog = MAX_LISTEN)
    65. {
    66. int ret = listen(_sockfd,backlog);
    67. if(ret < 0)
    68. {
    69. perror("listen error");
    70. return false;
    71. }
    72. return true;
    73. }
    74. //获取新建连接
    75. bool Accept(TcpSocket *sock,std::string *ip=NULL,uint16_t *port=NULL)
    76. {
    77. struct sockaddr_in addr;
    78. socklen_t len = sizeof(struct sockaddr_in);
    79. int newfd = accept(_sockfd,(struct sockaddr*)&addr,&len);
    80. if(newfd<0)
    81. {
    82. perror("accept error");
    83. return false;
    84. }
    85. sock->_sockfd = newfd;
    86. if(ip != NULL)
    87. {
    88. *ip = inet_ntoa(addr.sin_addr);
    89. }
    90. if(port != NULL)
    91. {
    92. *port = ntohs(addr.sin_port);
    93. }
    94. return true;
    95. }
    96. //接受数据
    97. bool Recv(std::string *body)
    98. {
    99. char tmp[4096] = {0};
    100. int ret = recv(_sockfd,tmp,4096,0);
    101. if(ret < 0)
    102. {
    103. perror("recv error");
    104. return false;
    105. }
    106. else if(ret == 0)
    107. {
    108. std::cout<<"peer shutdown!\n";
    109. return false;
    110. }
    111. body->assign(tmp,ret);//从tmp中截取ret长度大小的数据
    112. return true;
    113. }
    114. //发送数据
    115. bool Send(const std::string &body)
    116. {
    117. int ret;
    118. ret = send(_sockfd,body.c_str(),body.size(),0);
    119. if(ret < 0)
    120. {
    121. perror("send error");
    122. return false;
    123. }
    124. return true;
    125. }
    126. //关闭套接字
    127. bool Close()
    128. {
    129. if(_sockfd!= -1)
    130. {
    131. close(_sockfd);
    132. }
    133. return true;
    134. }
    135. };

    tcp_srv.cpp:

    1. #include "tcp_socket.hpp"
    2. int main()
    3. {
    4. TcpSocket lst_sock;
    5. //创建套接字
    6. CHECK_RES(lst_sock.Socket());
    7. lst_sock.SetReuseAddr();
    8. //绑定地址信息
    9. CHECK_RES(lst_sock.Bind("192.168.164.128",20000));
    10. //开始监听
    11. CHECK_RES(lst_sock.Listen());
    12. while(1)
    13. {
    14. //获取新建连接
    15. TcpSocket conn_sock;
    16. std::string cliip;
    17. uint16_t cliport;
    18. bool ret = lst_sock.Accept(&conn_sock,&cliip,&cliport);
    19. if(ret < 0)
    20. {
    21. continue;
    22. }
    23. std::cout<<"new connect:"<":"<
    24. //使用新建连接与客户端通信
    25. std::string buf;
    26. ret = conn_sock.Recv(&buf);
    27. if(ret == false)
    28. {
    29. conn_sock.Close();
    30. continue;
    31. }
    32. std::cout<<"client say:"<
    33. std::cout<<"server say:";
    34. fflush(stdout);
    35. std::cin>>buf;
    36. ret = conn_sock.Send(buf);
    37. if(ret == false)
    38. {
    39. conn_sock.Close();
    40. continue;
    41. }
    42. }
    43. // 关闭套接字
    44. lst_sock.Close();
    45. return 0;
    46. }

    tcp_cli.cpp:

    1. #include "tcp_socket.hpp"
    2. int main(int argc,char* argv[])
    3. {
    4. if(argc!= 3)
    5. {
    6. std::cout<<"please input server address!\n";
    7. std::cout<<"USsage:./tcp_cli 192.168.164.128 20000\n";
    8. return -1;
    9. }
    10. std::string srv_ip = argv[1];
    11. uint16_t srv_port = std::stoi(argv[2]);
    12. TcpSocket cli_sock;
    13. //创建套接字
    14. CHECK_RES(cli_sock.Socket());
    15. //绑定地址信息(客户端不推荐)
    16. //向服务器发起连接
    17. CHECK_RES(cli_sock.Connect(srv_ip,srv_port));
    18. while(1)
    19. {
    20. //与服务器通信
    21. std::string buf;
    22. std::cout<<"client say:";
    23. fflush(stdout);
    24. std::cin>>buf;
    25. bool ret = cli_sock.Send(buf);
    26. if(ret == false)
    27. {
    28. cli_sock.Close();
    29. return -1;
    30. }
    31. buf.clear();
    32. ret = cli_sock.Recv(&buf);
    33. if(ret == false)
    34. {
    35. cli_sock.Close();
    36. return -1;
    37. }
    38. std::cout<<"server say:"<
    39. }
    40. //关闭套接字
    41. cli_sock.Close();
    42. return 0;
    43. }

    makefile:

    1. all:tcp_srv tcp_cli
    2. tcp_cli:tcp_cli.cpp
    3. g++ -std=c++11 $^ -o $@
    4. tcp_srv:tcp_srv.cpp
    5. g++ -std=c++11 $^ -o $@
  • 相关阅读:
    【智能家居项目】裸机版本——项目介绍 | 输入子系统(按键) | 单元测试
    利用Jmeter做接口测试(功能测试)全流程分析
    并发之固定运行和交替运行方案
    文件操作~
    Oracle 的hint用法
    【设计模式】桥接模式
    在PyCharm中使用Jupyter Notebooks实现高效开发
    mac安装navicate
    小明OJ——字符串移位包含问题
    关系数据库系统中的 NULL 值及其用途
  • 原文地址:https://blog.csdn.net/weixin_46153828/article/details/126531466