TCP模拟实现

实现一个TCPSocket类

/*封装TCPSocket类,向外提供更加轻便的tcp套接字接口
 * 1.创建套接字     Socket()
 * 2.绑定地址信息   Bind(std::string &ip,uint16_t port)
 * 3.服务端开始监听,客户端向服务端发起连接请求   
    Listen(int backlog=5)   Connet(std::string& server_ip,uint16_t server_port)
 * 4.服务端获取已完成连接的客户端新socket     
    Accept(TCPSocket &clientsock,std::string &client_ip,uint16_t port)
 * 5.接受数据   Recv(std::string& buf)
 * 6.发送数据   Send(std::string& buf)
 * 7.关闭套接字   Close() 
 * */
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define CHECK_RET(q) if(q==false){return -1}  
class TCPSocket
{
public:
  TCPSocket():_sockfd(-1)
  {}
  ~TCPSocket()
  {}
  bool Socket()
  {
    _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(_sockfd<0)
    {
      perror("socket error");
      return false;
    }
    return true;
  }
  bool Bind(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=bind(_sockfd,(struct sockaddr*)&addr,len);
    if(ret<0)
    {
      perror("bind error");
      return false;
    }
    return true;
  }
  bool Listen(int backlog=5)
  {
    //int listen(int sockfd, int backlog);
    //backlog:最大并发连接数
    int ret=listen(_sockfd,backlog);
    if(ret<0)
    {
      perror("listen error");
      return false;
    }
    return true;
  }
  bool Accept(TCPSocket &client,std::string &client_ip,uint16_t &client_port)
  {
    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    //sockfd:套接字描述符
    //addr:新建连接的客户端地址信息
    //addrlen:新建客户端的地址信息长度
    //返回值:返回新建客户端socket的描述符
    struct sockaddr_in addr;
    socklen_t len=sizeof(struct sockaddr_in);
    int sockfd=accept(_sockfd,(struct sockaddr*)&addr,&len);
    if(sockfd<0)
    {
      perror("accept error");
      return false;
    }
    client.SetFd(sockfd);
    client_ip=inet_ntoa(addr.sin_addr);
    client_port=ntohs(addr.sin_port);
    return true;
  }
  void SetFd(int sockfd)
  {
    _sockfd=sockfd;
  }
  bool Connect(std::string &server_ip,uint16_t server_port)
  {
    //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    //sockfd:套接字描述符
    //addr:服务端地址信息
    //addrlen:地址信息长度
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port=htons(server_port);
    addr.sin_addr.s_addr=inet_addr(server_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 Recv(std::string &buf)
  {
    //ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    //sockfd:服务端为新客户端新建的socket描述符
    //flags:0-默认阻塞接收,没有数据就一直等待
    //    MSG_PEEK  接受数据,但是数据并不从接收缓冲区移除,常用于探测性数据接收
    //返回值:实际接收字节长度;  出错返回-1; 若连接断开则返回0
    //recv默认是阻塞的,意味着没有数据则一直等,不会返回0
    //返回0只有一种情况,就是连接断开,不能再继续通信了
    char tmp[4096];
    int ret=recv(_sockfd,tmp,4096,0);
    if(ret<0)
    {
      perror("recv error");
      return false;
    }
    else if(ret==0)
    {
      printf("peer shutdown\n");
      return false;
    }
    buf.assign(tmp,ret);
    return true;
  }
  bool Send(std::string &buf)
  {
    //ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    int ret=send(_sockfd,buf.c_str(),buf.size(),0);
    if(ret<0)
    {
      perror("send error");
      return false;
    }
    return true;
  }
  bool Close()
  {
    close(_sockfd);
    return true;
  }
private:
  int _sockfd;
};
int main()
{
  return 0;
}

TCP服务端程序

/*基于封装的TCPSocket,实现tcp服务端程序
 * 1.创建套接字
 * 2.为套接字绑定信息
 * 3.开始监听
 * while(1)
 * {
 *    4.从已完成连接队列,获取新建的客户端连接socket
 *    5.通过新建的客户端连接socket与指定的客户端进行通信,recv
 *    6.send
 * }
 * 7.关闭套接字*/
#include "tcpsocket.hpp"

int main(int argc,char* argv[])
{
  if(argc!=3)
  {
    std::cout<<"./tcp_server 192.168.32.130 9000\n";
    return -1;
  }
  std::string ip=argv[1];
  uint16_t port=atoi(argv[2]);

  TCPSocket sock;

  CHECK_RET(sock.Socket());
  CHECK_RET(sock.Bind(ip,port));
  CHECK_RET(sock.Listen());
  while(1)
  {
    TCPSocket clientsock;
    std::string client_ip;
    uint16_t client_port;
    if(sock.Accept(clientsock,client_ip,client_port)==false)
    {
      continue;
    }
    std::cout<<"new client:"<<client_ip<<":"<<client_port<<std::endl;
    std::string buf;
    clientsock.Recv(buf);
    std::cout<<"client say:"<<buf<<std::endl;
    buf.clear();
    std::cout<<"server say:";
    fflush(stdout);
    std::cin>>buf;
    clientsock.Send(buf);
  }
  sock.Close();
  return 0;
}


TCP客户端程序

/*基于封装的TCPSocket实现tcp客户端程序
 * 1.创建套接字
 * 2.为套接字绑定地址信息(不推荐用户手动绑定)
 * 3.向服务端发起连接请求
 * while(1)
 * {
 *    4.发送数据
 *    5.接受数据
 * }
 * 6.关闭套接字*/
#include "tcpsocket.hpp"
#include <signal.h>

void sigcb(int signo)
{
  printf("connection closed\n");
}
int main(int argc,char* argv[])
{
  if(argc!=3)
  {
    std::cout<<"./tcp_client 192.168.32.130 9000\n";
    return -1;
  }
  std::string ip=argv[1];
  uint16_t port=atoi(argv[2]);
  
  signal(SIGPIPE,sigcb);
  TCPSocket sock;
  CHECK_RET(sock.Socket());
  CHECK_RET(sock.Connect(ip,port));
  while(1)
  {
    std::string buf;
    std::cout<<"client say:";
    fflush(stdout);
    std::cin>>buf;
    sock.Send(buf);

    buf.clear();
    sock.Recv(buf);
    std::cout<<"server say:"<<buf<<std::endl;
  }
  sock.Close();
  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值