tcp通信

在这里插入图片描述

目录:

一.tcp概念

tcp也是一种通讯协议, 也是实现客户端和服务端通信的一种协议,只不过这个协议对于安全性的要求高.

二.通信流程&原理

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

三.接口理解

1.创建套接字 socket

在这里插入图片描述

2.绑定地址 bind

在这里插入图片描述

3.开始监听 listen

在这里插入图片描述

4.客户端发送连接请求 connect

在这里插入图片描述

5.服务端获取新建连接 accept

在这里插入图片描述

6.收发数据 send&recv

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

7.关闭套接字 close

在这里插入图片描述

四.代码封装tcp结构体

/*
TCP功能封装
将其功能封装实现后面的简单调用
*/
#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
//封装TCP协议所需要的函数
class TcpSocket{
    private:
        int _sockfd;    //私有是对应的描述符
    public:

        TcpSocket():_sockfd(-1){}   //构造函数将描述符初始化为-1
        //1.====创建套接字
        bool 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;
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);    //转成对应的网络字节序
            addr.sin_addr.s_addr = inet_addr(&ip[0]);
            socklen_t len = sizeof(sockaddr_in);    //字节大小
            int ret = bind(_sockfd, (sockaddr*)&addr, len); //调用接口实现数据的绑定
            if (ret < 0) {      //判断是否出错
                perror("bind error");
                return false;
            }
            return true;
        }
        //3.====开始监听
        bool Listen(int backlog = LISTEN_BACKLOG) {
            //listen(描述符,同一时间连接数)
            int ret = listen(_sockfd, backlog);
            if (ret < 0) {      //判断是否出错
                perror("listen error");
                return false;
            }
            return true;
        }
        //4.====客户端发送连接请求
        bool Connect(const std::string &ip,const int port) {
            sockaddr_in addr;       //引入对应需要用到的参数
            addr.sin_family = AF_INET;
            addr.sin_port = htons(port);
            addr.sin_addr.s_addr = inet_addr(&ip[0]);
            socklen_t len = sizeof(sockaddr_in);
            //connect(描述符,服务端地址, 地址长度)
            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;
            }
            //因为在这里将客户端和复制后的socket发生了连接,
            //这里就应该将对应的描述符指向与客户端连接的socket
            sock->_sockfd = newfd;  

            if (ip != NULL) {   
                *ip = inet_ntoa(addr.sin_addr);     //将对应的网络字节序的IP地址转成字符串点分十进制的IP地址
            }
            if (port != NULL) {
                *port = ntohs(addr.sin_port);       //对应的port为空,将对应的网络数据转换成对应的主机字节序
            }
            return true;
        }
        //6.====接受数据
        bool Recv(std::string *buf) {
            //int recv(描述符,空间,数据长度,标志位)
            //返回值:实际获取大小, 0-连接断开; -1-出错了
            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;
        }
        //7.====发送数据
        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;
        }
        //8.====关闭套接字
        bool Close() {
            if (_sockfd != -1) {        //存在则关闭
                close(_sockfd);
            }
            return true;
        }
};

封装函数就可以在写客户端和服务端比较简单,直接使用即可,这篇博客主要理解TCP是怎样实现和客户端的交互,从而实现通信的.

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值