socket---TCP通信

本文详细介绍了TCP通信的流程,包括服务器端的创建套接字、绑定地址、监听和接受连接,以及客户端的创建套接字、发起连接请求。同时,给出了C++实现TCP通信的类`TcpSocket`,包含套接字创建、绑定、监听、连接、接收和发送数据的方法。示例代码展示了客户端`tcp_cli.cpp`和服务器端`tcp_srv.cpp`如何使用该类进行通信。

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

TCP通信流程的编写:

通信流程:
Server:
1.创建套接字
2.为套接字绑定地址信息
3.开始监听
告诉系统可以开始处理客户端的连接请求。
系统会为每一个新客户创建一个新的套接字
4.获取新建连接
5. 收发数据(使用的是新建的套接字)
6. 关闭套接字
Client:
1.创建套接字
2. 为套接字绑定地址信息(不推荐主动绑定)
3.向服务端发起连接请求(开始监听之后)
4.收发数据
5.关闭套接字
接口认识:
1.创建套接字:int socket(int domain, int type, int protocol);
2.绑定地址:int bind(int sockfd, struct sockaddr *addr,socklen_t addrlen);
3.开始监听:int listen(int sockfd,int backlog);
sockfd:描述符backlog:服务端能够在同一时间处理的最大连接数
已完成连接队列的节点数量=backlog+1
tcpsocket.hpp

 #include<cstdio>                                                                                                                                                     
 #include<iostream>
 #include<string>
 #include<unistd.h>
 #include<arpa/inet.h>
 #include<netinet/in.h>
 #include<sys/socket.h>
 #define CHECK_RET(q)  if((q)==false){return -1;}
 #define LISTEN_BACKLOG 5
 class TcpSocket{
    private:
        int _sockfd; //套接字描述符
    public:
        TcpSocket():_sockfd(-1){}
        //1.建立套接字
        bool Socket(){
            //int socket(地址域类型,套接字类型,协议类型)
            _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(_sockfd<0){
              perror("socket error");
              return false;
            }
            return true;
        }
 
        //2.套接字绑定地址信息
        bool Bind(const std::string &ip,const uint16_t port){
            sockaddr_in addr;  //建立IPv4结构体
            addr.sin_family=AF_INET;  //设置地址域类型为IPv4
            addr.sin_port=htons(port);  //主机字节序端口转换为网络字节序端口
            addr.sin_addr.s_addr=inet_addr(&ip[0]); //将点分十进制转换为网络字节序
            socklen_t len=sizeof(sockaddr_in);
            //int bind(操作句柄,当前地址信息,地址信息长度)
            int ret=bind(_sockfd,(sockaddr*)&addr,len);
            if(ret<0){
              perror("bind error");
             return false;
            }
            return true;
        }
 
        //3.开始监听
        //int listen(描述符,同一时间连接数)
        bool Listen(int backlog=LISTEN_BACKLOG){
            int ret=listen(_sockfd,backlog);
            if(ret<0){
              perror("listen error");
              return false;
            }
            return true;
        }
 
        //4.客户端发送连接请求
        bool Connect(const std::string &ip,const uint16_t port){
            //int connect(描述符,服务端地址,地址长度)
            sockaddr_in addr;  //创建IPv4结构体
            addr.sin_family=AF_INET;  //地址域类型为IPv4
            addr.sin_port=htons(port); //主机字节序转换为网络字节序
            addr.sin_addr.s_addr=inet_addr(&ip[0]); //将点分十进制主机字节序转换为网络字节序
            socklen_t len=sizeof(sockaddr_in);
            int ret=connect(_sockfd,(sockaddr*)&addr,len);
            if(ret<0){
              perror("connect error");
              return false;
            }
            return true;
        }
 
        //5.服务端获取新连接
        bool Accept(TcpSocket *sock,std::string *ip=NULL,uint16_t *port=NULL){
             //int accept(监听套接字,客户端地址,长度)
             sockaddr_in addr;               
             socklen_t len=sizeof(sockaddr_in);
             int newfd=accept(_sockfd,(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;
        }
 
        //收发数据(tcp通信因为socket包含完整五元组因此不需要指定地址)
        bool Recv(std::string *buf){
             //int recv(描述符,空间,数据长度,标志位)
             char tmp[4096]={0};
             int ret=recv(_sockfd,tmp,4096,0);
             if(ret<0){
               perror("recv error");
               return false;
             }else if(ret==0){
               printf("peer shutdown");
               return false;
             }
             buf->assign(tmp,ret);
             return true;
        }
        bool Send(const std::string &data){
            //int send(描述符,数据,长度,标志位)
            int total=0;
            while(total<data.size()){      
              int ret=send(_sockfd,&data[0]+total,data.size()-total,0);
              if(ret<0){
                perror("send error");
                return false;
              }
              total+=ret;
            }
            return true;
        }
 
        //关闭连接
        bool Close(){
        if(_sockfd!=-1){
          close(_sockfd);
        }
        return true;
        }
 }; 

tcp_cli.cpp

1 #include"tcpsocket.hpp"
  2 
  3 int main(int argc,char *argv[])
  4 {
  5     //通过参数传入要连接的服务器的地址信息
  6     if(argc!=3){
  7       printf("usage:./tcp_cli srvip srvport\n");
  8       return -1;
  9     }
 10     std::string srvip=argv[1];
 11     uint16_t  srvport=std::stoi(argv[2]); //将字符串转换为十进制
 12 
 13     TcpSocket cli_sock;
 14     //1.创建套接字
 15     CHECK_RET(cli_sock.Socket());
 16     //2.绑定地址信息(不推荐)_
 17     //3.向服务端发起连接
 18     CHECK_RET(cli_sock.Connect(srvip,srvport));
 19     while(1){
 20       //4.接收数据
 21         std::string buf;
 22         std::cout<<"client say:";                                                                                                                                    
 23         std::cin>>buf;
 24         CHECK_RET(cli_sock.Send(buf));
 25 
 26         buf.clear();
 27         CHECK_RET(cli_sock.Recv(&buf));
 28         std::cout<<"server say:"<<buf<<std::endl;
 29     }
 30     //5.关闭套接字
 31     CHECK_RET(cli_sock.Close());
 32     return 0;
 33 }

tcp_srv.cpp

#include "tcpsocket.hpp"

int main(int argc, char *argv[])
{
    //通过程序运行参数指定服务端要绑定的地址
    // ./tcp_srv 192.168.2.2 9000
    if (argc != 3) {
        printf("usage: ./tcp_src 192.168.2.2 9000\n");
        return -1;
    }
    std::string srvip = argv[1];
    uint16_t srvport = std::stoi(argv[2]);
    TcpSocket lst_sock;//监听套接字
    //1. 创建套接字
    CHECK_RET(lst_sock.Socket());
    //2. 绑定地址信息
    CHECK_RET(lst_sock.Bind(srvip, srvport));
    //3. 开始监听
    CHECK_RET(lst_sock.Listen());
    while(1) {
        //4. 获取新建连接
        TcpSocket clisock;
        std::string cliip;
        uint16_t cliport;
        bool ret = lst_sock.Accept(&clisock, &cliip,&cliport);
        if (ret == false) {
            continue;
        }
        std::cout<<"get newconn:"<< cliip<<"-"<<cliport<<"\n";
        //5. 收发数据--使用获取的新建套接字进行通信
        std::string buf;
        ret = clisock.Recv(&buf);
        if (ret == false) {
            clisock.Close();
            continue;
        }
        std::cout << "client say: " << buf << std::endl;

        buf.clear();
        std::cout << "server say: ";
        std::cin >> buf;
        ret = clisock.Send(buf);
        if (ret == false) {
            clisock.Close();
        }
    }
    //6. 关闭套接字
    lst_sock.Close();
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值