tcp常用网络接口 linux环境

TCP(传输控制协议)网络通信是常见的网络应用形式,它提供了面向连接的、可靠的数据传输服务。TCP通信常用的接口主要包括以下几个方面:

常用接口

1. socket()

int socket(int domain, int type, int protocol);
  • 功能:打开一个网络通讯端口,并返回一个文件描述符(socket描述符)。
  • 参数
    • domain:地址族,对于IPv4,指定为AF_INET。
    • type:套接字类型,对于TCP协议,指定为SOCK_STREAM,表示面向流的传输协议。
    • protocol:传输层协议类型,对于TCP,通常指定为0。
  • 返回值:成功时返回文件描述符(非负整数),失败时返回-1。

2. bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 功能:将套接字与特定的网络地址(IP地址和端口号)绑定。
  • 参数
    • sockfd:由socket()返回的文件描述符。
    • myaddr:指向sockaddr结构体的指针,包含要绑定的地址和端口信息。
    • addrlen:地址结构体的长度。
  • 返回值:成功时返回0,失败时返回-1。

3. listen()

 int listen(int sockfd, int backlog);
  • 功能:使服务器端的套接字进入监听状态,准备接受客户端的连接请求。
  • 参数
    • sockfd:服务器端的套接字描述符。
    • backlog:设置等待连接队列的最大长度。
  • 返回值:成功时返回0,失败时返回-1。

4. accept()

 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 功能:接受一个客户端的连接请求,并返回一个新的套接字描述符,用于与该客户端进行通信。
  • 参数
    • sockfd:服务器端的监听套接字描述符。
    • addr:可选参数,用于存储客户端的地址信息。
    • addrlen:传入时表示addr的长度,传出时表示实际存储的客户端地址信息的长度。
  • 返回值:成功时返回新的套接字描述符,失败时返回-1。

5. connect()

 int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
  • 功能:客户端调用,用于建立与服务器端的连接。
  • 参数
    • sockfd:客户端的套接字描述符。
    • addr:指向服务器地址信息的sockaddr结构体指针。
    • addrlen:服务器地址结构体的长度。
  • 返回值:成功时返回0,失败时返回-1。

6. send() 和 recv()

 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
 ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 功能
    • send():用于向连接的套接字发送数据。
    • recv():用于从连接的套接字接收数据。
  • 参数
    • sockfd:套接字描述符。
    • buf:指向数据缓冲区的指针。
    • len:要发送或接收的数据长度。
    • flags:通常设置为0,表示默认行为。
  • 返回值
    • 对于send(),成功时返回实际发送的字节数,失败时返回-1。
    • 对于recv(),成功时返回实际接收的字节数,如果连接已关闭且没有数据可读,则返回0,出错时返回-1。

7. close()

 int close(int fd);
  • 功能:关闭套接字,释放相关资源。
  • 参数:套接字描述符。
  • 返回值:成功时返回0,失败时返回-1。

回显打印(熟悉一下接口)

大致流程

TCP服务器端流程

  1. 创建套接字(socket)
  2. 绑定套接字(bind)
  3. 监听连接(listen)
  4. 接受连接(accept)
  5. 数据传输(send/recv)
  6. 关闭套接字(close)

TCP客户端流程

  1. 创建套接字(socket)
  2. 连接服务器(connect)
  3. 数据传输(send/recv)
  4. 关闭套接字(close)

代码

ServerMain.cpp 服务器的主函数

#include "TcpServer.hpp"
#include<memory>
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " local-port" << std::endl;
        exit(0);
    }
    uint16_t port = std::stoi(argv[1]);
    std::unique_ptr<Tcpserver> tsvr = std::make_unique<Tcpserver>(port);
    tsvr->Initserver();
    tsvr->Loop();
    return 0;
}

TcpServer.hpp  对Tcp操作分装

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "InterAddr.hpp"
#include "Threadpool.hpp"
enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR
};
static const uint16_t gport = 8888;
static const int glisten = -1;
static const int gbacklog = 8;
using task_t = std::function<void()>;
class Tcpserver
{
public:
    Tcpserver(uint16_t port = gport)
        : _port(port), _listensockfd(glisten), _isrunning(false)
    {
    }
    void Initserver()
    {
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            std::cout << "socket error" << std::endl;
            exit(SOCKET_ERROR);
        }
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        if (bind(_listensockfd, (const sockaddr *)&local, sizeof(local)) < 0)
        {
            std::cout << "bind error" << std::endl;
            exit(BIND_ERROR);
        }
        if (::listen(_listensockfd, gbacklog) < 0)
        {
            std::cout << "listen error" << std::endl;
            exit(LISTEN_ERROR);
        }
        std::cout << "init success" << std::endl;
    }
    void Loop()
    {
        _isrunning = true;
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = ::accept(_listensockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                std::cout << "accpet error" << std::endl;
                exit(1);
            }
            InterAddr addr(client);
            std::cout<<"get a new link, client info"<<addr.AddrStr()<<std::endl;
            task_t f = std::bind(&Tcpserver::Service, this, sockfd, addr);
            ThreadPool<task_t>::GetInstance()->Equeue(f);
        }
        _isrunning = false;
    }
    void Service(int sockfd, InterAddr addr)
    {
        while (true)
        {
            char buffer[1024];
            ssize_t m = ::read(sockfd, buffer, sizeof(buffer) - 1);
            if (m > 0)
            {
                buffer[m] = 0;
                std::string echoserver = "[server echo]#";
                echoserver += buffer;
                ::write(sockfd, echoserver.c_str(), echoserver.size());
            }
            else if (m == 0)
            {
                std::cout << "clent quit " << addr.AddrStr() << std::endl;
                break;
            }
            else
            {
                std::cout << "read error" << std::endl;
                exit(1);
            }
        }
        ::close(sockfd);
    }
    ~Tcpserver()
    {
    }

private:
    uint16_t _port;
    int _listensockfd;
    bool _isrunning;
};

InterAddr.hpp LockGuard.hpp Thread.hpp Threadpool.hpp (字节序和线程池)

//interaddr.hpp
#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
class InterAddr
{
private:
    void ToHost(const struct sockaddr_in &addr)
    {
        port = ntohl(addr.sin_port);
        ip = inet_ntoa(addr.sin_addr);
    }

private:
    std::string ip;
    uint16_t port;
    struct sockaddr_in _addr;

public:
    InterAddr(const struct sockaddr_in &addr)
        : _addr(addr)
    {
        ToHost(addr);
    }
     bool operator == (const InterAddr &t)
    {
        return (this->ip == t.ip && this->port == t.port);
    }
    std::string Ip()
    {
        return ip;
    }
    uint16_t Port()
    {
        return port;
    }
    struct sockaddr_in Addr()
    {
        return _addr;
    }
    std::string AddrStr()
    {
        return ip + ":" + std::to_string(port);
    }
    ~InterAddr()
    {
    }
};

//LockGuard.hpp
#pragma once 
#include<pthread.h>
class LockGuard
{
private:
    /* data */
    pthread_mutex_t* _mutex;
public:
    LockGuard(pthread_mutex_t* mutex);
    ~LockGuard();
};

LockGuard::LockGuard(pthread_mutex_t* mutex):_mutex(mutex)
{
    pthread_mutex_lock(_mutex);
}

LockGuard::~LockGuard()
{
    pthread_mutex_unlock(_mutex);
}

//Thread.hpp
#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
namespace ThreadMoudle
{
    using func_t = std::function<void(const std::string &)>;
    class Thread
    {
    public:
        void Execute()
        {
            isrunning = true;
            _func(_name);
            isrunning = false;
        }

    public:
        Thread(const std::string name, func_t func)
            : _name(name), _func(func)
        {
        }
        static void *ThreadRoutine(void *args)
        {
            Thread *a = static_cast<Thread *>(args);
            a->Execute();
            return nullptr;
        }
        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, ThreadRoutine, (void *)this);
            if (n != 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        std::string Status()
        {
            if (isrunning)
            {
                return "running";
            }
            else
            {
                return "stop";
            }
        }
        void Stop()
        {
            if (isrunning)
            {
                pthread_cancel(_tid);
                isrunning = false;
            }
        }
        void Join()
        {
            pthread_join(_tid, nullptr);
        }
        std::string Name()
        {
            return _name;
        }
        ~Thread()
        {
        }

    private:
        std::string _name;
        pthread_t _tid;
        bool isrunning;
        func_t _func;
    };

} 

//Threadpool.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include "LockGuard.hpp"
#include "Thread.hpp"
using namespace ThreadMoudle;
static const int gdefaultnum = 5;
// pthread_mutex_t _fmtx=PTHREAD_MUTEX_INITIALIZER;
template <class T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void Wakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    void HandlerTask(const std::string name)
    {
        while (1)
        {
            LockQueue();
            while (IsEmpty() && _isrunning)
            {
                sleep_thread_num++;
                Sleep();
                sleep_thread_num--;
            }
            if (IsEmpty() && !_isrunning)
            {
                UnlockQueue();
                break;
            }
            T t = _task_queue.front();
            // std::cout<<&t<<std::endl;
            _task_queue.pop();
            UnlockQueue();
            // LockGuard lockguard(&_fmtx);
            t();
        }
    }
    void Init()
    {
        func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
        for (int i = 0; i < _thread_num; i++)
        {
            std::string name = "Thread-" + std::to_string(i + 1);
            _threads.emplace_back(name, func);
        }
    }
    void Start()
    {
        _isrunning = true;
        for (auto &threadd : _threads)
        {
            threadd.Start();
        }
    }
    ThreadPool(int thread_num = gdefaultnum)
        : _thread_num(thread_num), _isrunning(false), sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool<T> &) = delete;
    void operator=(const ThreadPool<T> &) = delete;

public:
    void Stop()
    {
        LockQueue();
        _isrunning = false;
        WakeupAll();
        UnlockQueue();
    }
    static ThreadPool<T> *GetInstance()
    {
        LockGuard lockguard(&_sig_mutex);
        if (_tp == nullptr)
        {
            _tp = new ThreadPool();
            _tp->Init();
            _tp->Start();
        }
        return _tp;
    }
    void Equeue(const T& in)
    {
        LockQueue();
        if (_isrunning)
        {
            _task_queue.push(in);
            if (sleep_thread_num > 0)
            {
                Wakeup();
            }
        }
        UnlockQueue();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _thread_num;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    bool _isrunning;
    int sleep_thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *_tp;
    static pthread_mutex_t _sig_mutex;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;

ClienMain.cpp 客户端

#include <iostream>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include "InterAddr.hpp"
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << "server-ip local-port" << std::endl;
        exit(0);
    }
    std::string serverip = argv[1];
    uint16_t port = std::stoi(argv[2]);
    int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
        exit(1);
    }
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    if (::inet_pton(AF_INET, serverip.c_str(), &server.sin_addr.s_addr) <= 0)
    {
        std::cerr << "inet_pton error" << std::endl;
        exit(1);
    }
    if (::connect(sockfd, (const struct sockaddr *)&server, sizeof(server)) < 0)
    {
        std::cerr << "connect error" << std::endl;
        exit(1);
    }
    while (true)
    {
        std::string message;
        std::cout<<"Enter #";
        std::getline(std::cin,message);
        ::write(sockfd,message.c_str(),message.size());
        char buffer[1024];
        int n=::read(sockfd,buffer,sizeof(buffer));
       if(n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer << std::endl;
        }
        else
        {
            break;
        }
    }
    ::close(sockfd);
    return 0;
}

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值