[Socket编程] 封装TCP实现一个socket类,实现客户端与服务端间的tcp通信


头文件(tcpsocket.hpp)

#include <string>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define CHECK_RET(q) if((q) == false){return -1;}

class TcpSocket{
    public:
        TcpSocket() : _sockfd(-1){}
        void SetSockFd(int fd){
            _sockfd = fd;
        }
        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 = 10) {
            //int listen(int sockfd, int backlog);
            //backlog:最大并发连接数--内核中已完成连接队列的最大节点数
            int ret = listen(_sockfd, backlog);
            if (ret < 0) {
                perror("listen error");
                return false;
            }
            return  true;
        }
        bool Connect(std::string &ip, uint16_t port) {
            //int connect(int fd, struct sockaddr *addr,socklen_t len);
            //addr: 要连接的服务端地址信息
            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 Accept(TcpSocket &sock, struct sockaddr_in *addr = NULL){
            //int accept(int sockfd, sockaddr *addr, socklen_t *len);
            //addr: 客户端的地址信息
            //len: 输入输出参数,既要指定接收长度,还要接收实际长度
            //返回值:为新客户端新建的socket套接字描述符
            //通过这个返回的描述符可以与指定的客户端进行通信
            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;
            }
            if (addr != NULL) {
                memcpy(addr, &_addr, len);
            }
            sock.SetSockFd(newfd);
            //_sockfd--仅用于接收新客户端连接请求
            //newfd----专门用于与客户端进行通信
            return true;
        }
        bool Recv(std::string &buf) {
            char tmp[4096] = {0};
            //ssize_t recv(int sockfd, void *buf, size_t len, int flags)
            //flags:0-默认阻塞接收  MSG_PEEK-获取数据但是不从缓冲区移除
            //返回值:实际接收的数据长度    失败:-1    连接断开:0
            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, 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);
            _sockfd = -1;
        }
    private:
        int _sockfd;
};

客户端(tcp_client.cpp)

#include <iostream>
#include "tcpsocket.hpp"

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

    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;
}

服务器(tcp_server.cpp)

#include <iostream>
#include "tcpsocket.hpp"
int main(int argc, char *argv[]){
    if (argc != 3) {
        printf("./tcp_srv ip  port\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 clisock;
        struct sockaddr_in cliaddr;
        //accept是阻塞获取已经完成的连接
        if (sock.Accept(clisock, &cliaddr) == false) {
            continue;
        }
        printf("new connect client:%s:%d\n", 
                inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
        std::string buf;
        clisock.Recv(buf);
        printf("client say:%s\n", buf.c_str());

        buf.clear();
        std::cout<<"server say:";
        fflush(stdout);
        std::cin>>buf;
        clisock.Send(buf);
    }
    sock.Close();
    return 0;
}
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

giturtle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值