tcp通信

Posted 小羊教你来编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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是怎样实现和客户端的交互,从而实现通信的.

以上是关于tcp通信的主要内容,如果未能解决你的问题,请参考以下文章

与另一个片段通信的片段接口

TCP通信的客户端代码实现,TCP通信的服务端代码实现

无法通过接口获取与片段通信的活动

Python 之 Socket编程(TCP/UDP)

Java网络编程 - TCP通信

tcp通信