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

本文介绍了一个简单的TCP服务器与客户端实现,重点在于如何管理TCP连接状态,包括处理TIME_WAIT状态以快速重启服务器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

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:

#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>

#define MAX_LISTEN 5
#define CHECK_RES(q) if((q)==false) { return -1;}
class TcpSocket{
   private:
       int _sockfd;
   public:
       TcpSocket():_sockfd(-1){}

   void SetReuseAddr()
   {
    int opt = 1;
    setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(int));
  }
    //创建套接字  
     bool Socket()
       {
         _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
         if(_sockfd < 0)
         {
           perror("socket error");
           return false;
         }
       return true;
       }

   //绑定地址信息
       bool Bind(const std::string &ip,uint16_t port)
       {
         struct sockaddr_in addr;//先定义一个ipv4的地址结构
         addr.sin_family = AF_INET;
         addr.sin_port = htons(port);
         addr.sin_addr.s_addr = inet_addr(ip.c_str());
         socklen_t len = sizeof(struct sockaddr_in);
         int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
         if(ret<0)
         {
            perror("bind error");
            return false;
         }
         return true;
         }

    //向服务器发起连接
      bool Connect(const std::string &ip,uint16_t port)
     {
        struct sockaddr_in addr;
       addr.sin_family = AF_INET;
       addr.sin_port = htons(port);
       addr.sin_addr.s_addr = inet_addr(ip.c_str());
       socklen_t len = sizeof(struct sockaddr_in);
       int ret = connect(_sockfd,(struct sockaddr*)&addr,len);
       if(ret < 0)
         {
           perror("connect error");
           return false;
         }
       return true;
     }
     
   //服务器开始监听
    bool Listen(int backlog = MAX_LISTEN)
     {
      int ret = listen(_sockfd,backlog);
      if(ret < 0)
      {
        perror("listen error");
        return false;
      }
     return true;
    }

  //获取新建连接
    bool Accept(TcpSocket *sock,std::string *ip=NULL,uint16_t *port=NULL)
    {
     struct sockaddr_in addr;
     socklen_t len = sizeof(struct sockaddr_in);
     int newfd = accept(_sockfd,(struct sockaddr*)&addr,&len);
     if(newfd<0)
       {
        perror("accept error");
        return false;
       }
     sock->_sockfd = newfd;
     if(ip != NULL)
      {
        *ip = inet_ntoa(addr.sin_addr);
      }
     if(port != NULL)
      {
        *port = ntohs(addr.sin_port);
      }
     return true;
    }

   //接受数据
  bool Recv(std::string *body)
  {
   char tmp[4096] = {0};
   int ret = recv(_sockfd,tmp,4096,0);
   if(ret < 0)
   {
    perror("recv error");
    return false;
   }
   else if(ret == 0)
   {
    std::cout<<"peer shutdown!\n";
    return false;
   }
   body->assign(tmp,ret);//从tmp中截取ret长度大小的数据
   return true;
 }



   //发送数据
    bool Send(const std::string &body)
    {
       int ret;
       ret = send(_sockfd,body.c_str(),body.size(),0);
       if(ret < 0)
       {
         perror("send error");
         return false;
       }
     return true;
    }

  //关闭套接字
  bool Close()
  {
    if(_sockfd!= -1)
    {
      close(_sockfd);
    }
   return true;
  }
  



};

tcp_srv.cpp:

#include "tcp_socket.hpp"
int main()
{
  TcpSocket lst_sock;

  //创建套接字
   CHECK_RES(lst_sock.Socket());
  lst_sock.SetReuseAddr();

  //绑定地址信息
   CHECK_RES(lst_sock.Bind("192.168.164.128",20000));
  //开始监听
   CHECK_RES(lst_sock.Listen());
   while(1)
   {
    //获取新建连接
     TcpSocket conn_sock;
     std::string cliip;
     uint16_t cliport;
     bool ret = lst_sock.Accept(&conn_sock,&cliip,&cliport);
     if(ret < 0)
     {
      continue;
     }
    std::cout<<"new connect:"<<cliip<<":"<<cliport<<std::endl;
     //使用新建连接与客户端通信
     std::string buf;
     ret = conn_sock.Recv(&buf);
     if(ret == false)
     {
      conn_sock.Close();
      continue;
     }
      std::cout<<"client say:"<<buf<<std::endl;
      std::cout<<"server say:";
      fflush(stdout);
      std::cin>>buf;
      ret = conn_sock.Send(buf);
      if(ret == false)
      {
       conn_sock.Close();
       continue;
      }
     }
   
   // 关闭套接字
   lst_sock.Close();
   return 0;
  }

tcp_cli.cpp:

#include "tcp_socket.hpp"

int main(int argc,char* argv[])
{
  if(argc!= 3)
  {
    std::cout<<"please input server address!\n";
    std::cout<<"USsage:./tcp_cli 192.168.164.128 20000\n";
    return -1;
  }
 std::string srv_ip = argv[1];
 uint16_t srv_port = std::stoi(argv[2]);
 TcpSocket cli_sock;
 //创建套接字
   CHECK_RES(cli_sock.Socket());
 //绑定地址信息(客户端不推荐)
 //向服务器发起连接
   CHECK_RES(cli_sock.Connect(srv_ip,srv_port));
   while(1)
   {
     //与服务器通信
     std::string buf;
     std::cout<<"client say:";
     fflush(stdout);
     std::cin>>buf;
     bool ret = cli_sock.Send(buf);
    if(ret == false)
    {
     cli_sock.Close();
     return -1;
    }
    buf.clear();
    ret = cli_sock.Recv(&buf);
    if(ret == false)
    {
     cli_sock.Close();
     return -1;
    }
    std::cout<<"server say:"<<buf<<std::endl;
  }
 //关闭套接字
  cli_sock.Close();
  return 0;
 }
   
  

makefile:

all:tcp_srv tcp_cli
tcp_cli:tcp_cli.cpp
	g++ -std=c++11 $^ -o $@
tcp_srv:tcp_srv.cpp
	g++ -std=c++11 $^ -o $@
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值