Tcp Socket

Tcp套接字的使用和Udp套接字的使用是差不多的,但是有一些地方还是有差别的,直接上代码

cpp 复制代码
#pragma once
#include <iostream>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


std::string DefaultIp = "127.0.0.1";
int DefaultPort = 8080;
#define BACKLOG 5
class TcpSerevr
{
public:
    TcpSerevr(const std::string& Ip = DefaultIp, const int &Port = DefaultPort)
        //:_Ip(Ip)
        :_Port(Port)
        ,_ListenSockFd(-1)
        ,_IsRuning(false)
    {

    }
    void Init()
    {
        //创建套接字
        _ListenSockFd = socket(AF_INET, SOCK_STREAM, 0);
        if(_ListenSockFd < 0)
        {
            std::cout << "socket error: " << strerror(errno) << std::endl;
            exit(1);
        }
        std::cout << "Socket success" << std::endl;

        //初始化地址
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_Port);
        //local.sin_addr.s_addr = inet_addr(_Ip.c_str());
        local.sin_addr.s_addr = INADDR_ANY;
        //绑定
        int n = bind(_ListenSockFd, (const struct sockaddr*)&local, sizeof(local));
        if(n < 0)
        {
            std::cout << "bind error: " << strerror(errno) << std::endl;
            exit(1);
        }
        std::cout << "bind sucess" << std::endl;

        //设置监听
        n = listen(_ListenSockFd, BACKLOG);
        if(n < 0)
        {
            std::cout << "listen error: " << strerror(errno) << std::endl;
            exit(1);
        }
        std::cout << "listen success" << std::endl;
    }
    void HanderRequest(int SockFd)
    {
        while(true)
        {
            char Buffer[1024];
            ssize_t n = read(SockFd, Buffer, sizeof(Buffer)-1);
            if(n > 0)
            {
                Buffer[n] = 0;
                std::string EchoStr = "Server say:";
                EchoStr += Buffer;
                write(SockFd, EchoStr.c_str(), EchoStr.size());
            }
        }
    }
    void Start()
    {
        _IsRuning = true;
        while(_IsRuning)
        {
            struct sockaddr_in Src;
            socklen_t len = sizeof(Src);
            int SockFd = accept(_ListenSockFd, (struct sockaddr*)&Src, &len);
            if(SockFd < 0)
            {
                std::cout << "accept error: " << strerror(errno) << std::endl;
                continue;
            }
            std::cout << "accept sucess" << std::endl;
            HanderRequest(SockFd);
        }
        _IsRuning = false;
    }
private:
    //std::string _Ip;
    int _Port;
    int _ListenSockFd;
    bool _IsRuning;
};

Init函数

在上面的init函数中,有这样一句代码

cpp 复制代码
 //设置监听
 n = listen(_ListenSockFd, BACKLOG);
 if(n < 0)
 {
     std::cout << "listen error: " << strerror(errno) << std::endl;
     exit(1);
 }
 std::cout << "listen success" << std::endl;

因为Tcp协议是面向连接的,所以在初始化的时候需要监听

Start函数

在Start函数中,需要accept,其中,有个参数为sockfd类型的,返回值也是sockfd类型的,参数里面是用来监听的,返回的值是用为Tcp服务器服务

cpp 复制代码
struct sockaddr_in Src;
socklen_t len = sizeof(Src);
int SockFd = accept(_ListenSockFd, (struct sockaddr*)&Src, &len);

客户端函数

cpp 复制代码
#include <iostream>
#include <cstring>
#include <memory>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        std::cout << "Usage ./TcpClient IP Port" << std::endl;
        return 0;
    }
    std::string Ip = argv[1];
    int Port = std::atoi(argv[2]);
    int SockFd = socket(AF_INET, SOCK_STREAM, 0);
    if(SockFd < 0)
    {
        std::cout << "socket error" << std::endl;
        return 0;
    }
    std::cout << "socket sucess" << std::endl;

    struct sockaddr_in ServerAddr;
    memset(&ServerAddr, 0, sizeof(ServerAddr));
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(Port);
    ServerAddr.sin_addr.s_addr = inet_addr(Ip.c_str());
    
    int n = connect(SockFd, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
    if(n < 0)
    {
        std::cout << "connect error" << std::endl;
        return 0;
    }

    while(true)
    {
        std::string Message;
        std::cout << "please send message#: ";
        std::getline(std::cin, Message);
        int n = write(SockFd, Message.c_str(), Message.size());
        if(n > 0)
        {
            char Buffer[1024];
            int m = read(SockFd, Buffer, sizeof(Buffer));
            if(m > 0)
            {
                Buffer[m] = 0;
                std::cout << Buffer << std::endl; 
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }

    }
    close(SockFd);

    return 0;
}

客户端同样和Udp的有区别

cpp 复制代码
 int n = connect(SockFd, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
 if(n < 0)
 {
    std::cout << "connect error" << std::endl;
    return 0;
 }

需要连接

相关推荐
2401_868534782 小时前
网络安全:信息加密、认证(鉴别)、数字签名(CA)、密钥安全分发
网络·网络协议
运维行者_10 小时前
企业无线网络监控的挑战与智能化演进趋势
大数据·运维·服务器·网络·数据库
国强_dev11 小时前
技术探讨:使用 stunnel 加密转发数据库连接时,如何获取客户端真实 IP?
数据库·网络协议·tcp/ip
Coder_Shenshen12 小时前
西门子S7CommPlus协议鉴权算法原理与流程详解
网络·后端·算法
HavenlonLabs15 小时前
Havenlon 对抗性完整(十七):安全不是“防住攻击”,而是控制失败方式
网络·人工智能·架构·安全威胁分析·安全架构·havenlon
fei_sun15 小时前
路径MTU发现
linux·运维·网络
tachibana217 小时前
hot100 回文链表(234)
java·网络·数据结构·leetcode·链表
从零开始的代码生活_18 小时前
NAT、代理服务与内网穿透详解
linux·服务器·网络·c++·http·智能路由器
云栖梦泽在18 小时前
Claude Code / Codex 使用卡顿怎么办?AI 编程 Agent 连接失败与网络排查思路
网络·人工智能·网络协议·chatgpt·性能优化