【Linux】Socket编程TCP

目录

一、TCP相关的接口

[二、Echo Server](#二、Echo Server)

多进程版

多线程版

线程池版

三、多线程远程命令执行


一、TCP相关的接口

  • listen函数

功能:将套接字设置为"监听模式",使其能够接受客户端的连接请求。

原型:int listen(int sockfd, int backlog);

参数说明:

  • sockfd:套接字的文件描述符。
  • backlog:指定在拒绝新连接之前,系统允许的最大未接受连接数量(即连接队列的长度)。例如:backlog = 6,服务器最多可排队6个未处理的连接请求。

返回值:成功返回0,失败返回-1 并设置errno。

注意:

  • 在TCP协议中,服务器需要先调用bind绑定地址和端口,然后调用listen开始监听。
  • accept函数

功能:服务器端接受客户端的连接请求。

原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明:

  • sockfd:监听套接字的文件描述符(通过socket()创建且以调用listen()进入监听状态)
  • addr:指向sockaddr结构体的指针,用于存储客户端地址信息(IP和端口)。设为NULL表示不获取地址。
  • addrlen:是一个传入参数,传入的是调用者提供的,缓冲区addr的长度以及缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满缓冲区)。

返回值:成功返回新创建的通信套接字描述符(非负整数),用于后续数据传输;失败返回-1并设置errno。

注意:

  • 必须在listen之后再调用accept函数。
  • 当服务器调用accept函数时没有客户端的连接请求,就阻塞等待直到有客户端连接请求。
  • connect函数

功能:用于客户端套接字发起连接请求,目标是与指定服务器建立可靠的TCP连接。

原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

  • sockfd:套接字描述符
  • addr:用于指定服务器的IP地址和端口号
  • addrlen:表示addr结构体的长度

返回值:成功返回0,表示连接成功建立;失败返回-1并设置errno。

  • recv函数

功能:用于从已连接的套接字接收数据,常用语TCP协议通信。

原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数说明:

  • sockfd:套接字描述符
  • buf:指向缓冲区的指针,用于存储接收到的数据。
  • len:缓冲区大小,表示可以接收的最大字节数。
  • flags:标志位,控制接收行为,常见值如0(默认行为)或MSG_WAITALL(等待所有数据到达)

返回值:成功返回接收到的字节数,失败返回-1并设置errno。

  • send函数

功能:用于通过已连接的套接字发送数据(TCP协议)。

原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);

参数说明:

  • sockfd:已建立连接的套接字描述符(由socket()创建且connect()成功的套接字)
  • buf:指向待发送数据缓冲区的指针
  • len:待发送数据的字节长度
  • flags:控制发送行为的标志位(常用值):0:默认阻塞模式;MSG_DONTWAIT:非阻塞发送;MSG_OOB:发送带外数据(紧急数据);MSG_NOSIGNAL:禁止生成SIGPIPE信号

返回值:成功返回实际发送的字节数(可能小于len),失败返回-1并设置errno。

二、Echo Server

cpp 复制代码
// Comm.hpp

#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

enum{
    Usage_Err = 1,
    Socket_Err,
    Bind_Err,
    Listen_Err
};

#define CONV(addr_ptr) ((struct sockaddr *)addr_ptr)
cpp 复制代码
// nocopy.hpp

#pragma once

class nocopy
{
public:
    nocopy(){}
    nocopy(const nocopy&) = delete;
    nocopy& operator=(const nocopy&) = delete;
    ~nocopy(){}
};
cpp 复制代码
// TcpServer.hpp

#pragma once

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"

using namespace LogModule;

const static int default_backlog = 6;
const static int default_listenfd = -1;

class TcpServer : public nocopy
{
public:
    TcpServer(uint16_t port, int backlog = default_backlog)
    :_port(port), _listenfd(default_listenfd), _backlog(default_backlog), _running(false){}

    void Init() {
        // 创建socket
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd < 0) {
            LOG(LogLevel::ERROR) << "create socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogLevel::INFO) << "create socket success, sockfd: " << _listenfd;

        // bind
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);

        ssize_t n = bind(_listenfd, CONV(&local), sizeof(local));
        if(n < 0) {
            LOG(LogLevel::ERROR) << "socket bind error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Bind_Err);
        }
        LOG(LogLevel::INFO) << "bind socket success!!!";

        // 设置 socket 为监听状态
        n = listen(_listenfd, _backlog);
        if(n < 0) {
            LOG(LogLevel::ERROR) << "listen socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Listen_Err);
        }
        LOG(LogLevel::INFO) << "listen socket success!!!";
    }

    void Start() {
        _running = true;
        while(_running) {
            // 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, CONV(&peer), &len);
            if(sockfd < 0) {
                LOG(LogLevel::WARNING) << "accept socket error, errno: " << errno << ", error string: " << strerror(errno);
                continue;
            }
            LOG(LogLevel::INFO) << "accept socket success, sockfd: " << sockfd;

            // 提供服务
            Server(sockfd);
            close(sockfd);
        }
    }
private:
    void Server(int sockfd) {
        char buffer[4096];
        // 一直进行IO操作
        while(true) {
            // 可以使用文件的读写接口直接进行通信
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0) {
                buffer[n] = 0;
                std::cout << "client say# " << buffer << std::endl;

                std::string echo = "server echo# ";
                echo += buffer;
                write(sockfd, echo.c_str(), echo.size());
            }
            else if(n == 0) { // 说明读到结尾,关闭连接
                LOG(LogLevel::INFO) << "client quit...";
                break;
            }
            else { // 文件读取出现错误
                LOG(LogLevel::ERROR) << "read sockfd error, errno: " << errno << ", error string: " << strerror(errno);
                break;
            }
        }
    }
private:
    uint16_t _port;
    int _listenfd;
    int _backlog;
    bool _running;
};
cpp 复制代码
// TcpServer.cc

#include "TcpServer.hpp"

int main(int argc, char* argv[])
{
    if(argc != 2) {
        std::cerr << "Usage: " << argv[0] << " server_port" << std::endl;
        return 1;
    }

    uint16_t port = atoi(argv[1]);
    TcpServer ts(port);
    ts.Init();
    ts.Start();
    return 0;
}
cpp 复制代码
// TcpClient.cc

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include "Comm.hpp"

int main(int argc, char* argv[])
{
    if(argc != 3) {
        std::cout << "Usage: " << argv[0] << " server_ip server_port" << std::endl;
        return 1;
    }

    uint16_t port = std::atoi(argv[2]);
    std::string ip = argv[1];

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0) {
        std::cerr << "create socket error" << std::endl;
        return 2;
    }

    // 跟UDP一样,需要bind,但不需要用户显示bind,client系统随机端口
    // 发起连接时,client会被系统自动进行本地bind
    // connect
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    inet_pton(AF_INET, ip.c_str(), &server.sin_addr);

    int n = connect(sockfd, CONV(&server), sizeof(server)); // 自动bind
    if(n < 0) {
        std::cerr << "connect error" << std::endl;
        return 3;
    }

    while(true) {
        std::string inbuffer;
        std::cout << "Please Enter: ";
        std::getline(std::cin, inbuffer);

        ssize_t n = write(sockfd, inbuffer.c_str(), inbuffer.size());
        if(n > 0) {
            char buffer[4096];
            ssize_t m = read(sockfd, buffer, sizeof(buffer) - 1);
            if(m > 0) {
                buffer[m] = 0;
                std::cout << "get a echo message: " << buffer << std::endl;
            }
            else break;
        }
        else break;
    }

    return 0;
}

由于客户端不需要固定的端口号,因此不用调用 bind 函数,客户端端口由内核自动分配。

注意:

  • 客户端不是不允许调用bind,只是没有必要显示调用bind固定一个端口号。否则在同一台机器上启动多个客户端,机会出现端口号被占用导致无法正确建立连接。
  • 服务器也不是必须调用bind,但如果服务器不调用bind,内核会自动给服务器分配监听端口,每次启动服务器时端口号都不一样,客户端要连接服务器就会遇到麻烦。

测试多个连接的情况

我们在启动一个客户端,尝试连接服务器,发现第二个客户端不能正确的和服务器进行通信。

原因:是因为我们 accept 一个请求后,就一直在 while 中循环尝试 read,没有继续调用 accept,导致无法接受新的请求。

我们当前的TCP服务器只能与一个客户端通信,这是不科学的。

多进程版

对于每个请求,创建子进程的方式来支持多连接。

cpp 复制代码
// TcpServer.hpp

#pragma once

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/wait.h>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"

using namespace LogModule;

const static int default_backlog = 6;
const static int default_listenfd = -1;

class TcpServer : public nocopy
{
public:
    TcpServer(uint16_t port, int backlog = default_backlog)
    :_port(port), _listenfd(default_listenfd), _backlog(default_backlog), _running(false){}

    void Init() {
        // 创建socket
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd < 0) {
            LOG(LogLevel::ERROR) << "create socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogLevel::INFO) << "create socket success, sockfd: " << _listenfd;

        // bind
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);

        ssize_t n = bind(_listenfd, CONV(&local), sizeof(local));
        if(n < 0) {
            LOG(LogLevel::ERROR) << "socket bind error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Bind_Err);
        }
        LOG(LogLevel::INFO) << "bind socket success!!!";

        // 设置 socket 为监听状态
        n = listen(_listenfd, _backlog);
        if(n < 0) {
            LOG(LogLevel::ERROR) << "listen socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Listen_Err);
        }
        LOG(LogLevel::INFO) << "listen socket success!!!";
    }

    void Start() {
        _running = true;
        while(_running) {
            // 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, CONV(&peer), &len);
            if(sockfd < 0) {
                LOG(LogLevel::WARNING) << "accept socket error, errno: " << errno << ", error string: " << strerror(errno);
                continue;
            }
            LOG(LogLevel::INFO) << "accept socket success, sockfd: " << sockfd;

            ProcessConnect(sockfd);
        }
    }
private:
    void ProcessConnect(int sockfd) {
        int id = fork();
        if(id < 0) {
            LOG(LogLevel::ERROR) << "fork error";
            close(sockfd);
            return;
        }
        else if(id == 0) {
            // 子进程
            close(_listenfd);
            if(fork() > 0) exit(0); // 子进程创建一个子进程,并退出,让创建出的子进程变为孤儿进程,由系统管理
            // 孤儿进程
            // 提供服务
            Server(sockfd);
            close(sockfd);
            exit(0);
        }
        else {
            close(sockfd);
            waitpid(id, nullptr, 0);
        }
    }

    void Server(int sockfd) {
        char buffer[4096];
        // 一直进行IO操作
        while(true) {
            // 可以使用文件的读写接口直接进行通信
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0) {
                buffer[n] = 0;
                std::cout << "client say# " << buffer << std::endl;

                std::string echo = "server echo# ";
                echo += buffer;
                write(sockfd, echo.c_str(), echo.size());
            }
            else if(n == 0) { // 说明读到结尾,关闭连接
                LOG(LogLevel::INFO) << "client quit...";
                break;
            }
            else { // 文件读取出现错误
                LOG(LogLevel::ERROR) << "read sockfd error, errno: " << errno << ", error string: " << strerror(errno);
                break;
            }
        }
    }
private:
    uint16_t _port;
    int _listenfd;
    int _backlog;
    bool _running;
};

多线程版

cpp 复制代码
// TcpServer.hpp

#pragma once

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/wait.h>
#include <pthread.h>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"

using namespace LogModule;

const static int default_backlog = 6;
const static int default_listenfd = -1;

class TcpServer : public nocopy
{
public:
    TcpServer(uint16_t port, int backlog = default_backlog)
    :_port(port), _listenfd(default_listenfd), _backlog(default_backlog), _running(false){}

    void Init() {
        // 创建socket
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd < 0) {
            LOG(LogLevel::ERROR) << "create socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogLevel::INFO) << "create socket success, sockfd: " << _listenfd;

        // bind
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);

        ssize_t n = bind(_listenfd, CONV(&local), sizeof(local));
        if(n < 0) {
            LOG(LogLevel::ERROR) << "socket bind error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Bind_Err);
        }
        LOG(LogLevel::INFO) << "bind socket success!!!";

        // 设置 socket 为监听状态
        n = listen(_listenfd, _backlog);
        if(n < 0) {
            LOG(LogLevel::ERROR) << "listen socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Listen_Err);
        }
        LOG(LogLevel::INFO) << "listen socket success!!!";
    }

    void Start() {
        _running = true;
        while(_running) {
            // 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, CONV(&peer), &len);
            if(sockfd < 0) {
                LOG(LogLevel::WARNING) << "accept socket error, errno: " << errno << ", error string: " << strerror(errno);
                continue;
            }
            LOG(LogLevel::INFO) << "accept socket success, sockfd: " << sockfd;

            pthread_t tid;
            pthread_create(&tid, nullptr, ProcessConnect, (void*)&sockfd);
        }
    }

    static void Server(int sockfd) {
        char buffer[4096];
        // 一直进行IO操作
        while(true) {
            // 可以使用文件的读写接口直接进行通信
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0) {
                buffer[n] = 0;
                std::cout << "client say# " << buffer << std::endl;

                std::string echo = "server echo# ";
                echo += buffer;
                write(sockfd, echo.c_str(), echo.size());
            }
            else if(n == 0) { // 说明读到结尾,关闭连接
                LOG(LogLevel::INFO) << "client quit...";
                break;
            }
            else { // 文件读取出现错误
                LOG(LogLevel::ERROR) << "read sockfd error, errno: " << errno << ", error string: " << strerror(errno);
                break;
            }
        }
    }
private:
    static void* ProcessConnect(void* arg) {
        pthread_detach(pthread_self());
        int* sockptr = static_cast<int*>(arg);
        TcpServer::Server(*sockptr);
        close(*sockptr);
        delete sockptr;
        return nullptr;
    }
private:
    uint16_t _port;
    int _listenfd;
    int _backlog;
    bool _running;
};

线程池版

cpp 复制代码
#pragma once

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/wait.h>
#include <pthread.h>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"
#include "ThreadPool.hpp"

using namespace LogModule;

const static int default_backlog = 6;
const static int default_listenfd = -1;

class TcpServer : public nocopy
{
public:
    TcpServer(uint16_t port, int backlog = default_backlog)
    :_port(port), _listenfd(default_listenfd), _backlog(default_backlog), _running(false){}

    void Init() {
        // 创建socket
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd < 0) {
            LOG(LogLevel::ERROR) << "create socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogLevel::INFO) << "create socket success, sockfd: " << _listenfd;

        // bind
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);

        ssize_t n = bind(_listenfd, CONV(&local), sizeof(local));
        if(n < 0) {
            LOG(LogLevel::ERROR) << "socket bind error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Bind_Err);
        }
        LOG(LogLevel::INFO) << "bind socket success!!!";

        // 设置 socket 为监听状态
        n = listen(_listenfd, _backlog);
        if(n < 0) {
            LOG(LogLevel::ERROR) << "listen socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Listen_Err);
        }
        LOG(LogLevel::INFO) << "listen socket success!!!";
    }

    void Start() {
        using task_t = std::function<void()>;
        _running = true;
        while(_running) {
            // 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, CONV(&peer), &len);
            if(sockfd < 0) {
                LOG(LogLevel::WARNING) << "accept socket error, errno: " << errno << ", error string: " << strerror(errno);
                continue;
            }
            LOG(LogLevel::INFO) << "accept socket success, sockfd: " << sockfd;

            task_t t = std::bind(&TcpServer::Server, sockfd);
            ThreadPool<task_t>::GetInstance()->Push(t);
        }
    }

    static void Server(int sockfd) {
        char buffer[4096];
        // 一直进行IO操作
        while(true) {
            // 可以使用文件的读写接口直接进行通信
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0) {
                buffer[n] = 0;
                std::cout << "client say# " << buffer << std::endl;

                std::string echo = "server echo# ";
                echo += buffer;
                write(sockfd, echo.c_str(), echo.size());
            }
            else if(n == 0) { // 说明读到结尾,关闭连接
                LOG(LogLevel::INFO) << "client quit...";
                break;
            }
            else { // 文件读取出现错误
                LOG(LogLevel::ERROR) << "read sockfd error, errno: " << errno << ", error string: " << strerror(errno);
                break;
            }
        }
    }
private:
    uint16_t _port;
    int _listenfd;
    int _backlog;
    bool _running;
};

三、多线程远程命令执行

cpp 复制代码
// Command.hpp

#pragma once

#include <iostream>
#include <string>
#include <unordered_set>
#include <unistd.h>
#include <sys/socket.h>

class Command
{
public:
    Command(int sockfd):_sockfd(sockfd){
        // 只允许少量命令执行,只是做一个简单的示范,有兴趣可以和之前实现的简单的shell程序结合
        _hash_com.insert("ls");
        _hash_com.insert("ls -l");
        _hash_com.insert("pwd");
        _hash_com.insert("whoami");
    }

    bool IsExist(std::string command) {
        return _hash_com.find(command) != _hash_com.end();
    }

    std::string Excute(std::string &command) {
        if(!IsExist(command)) return std::string();
        FILE* fp = popen(command.c_str(), "r");
        if(fp == nullptr) return std::string();
        char buffer[1024];
        std::string res;
        while(fgets(buffer, sizeof(buffer), fp))
            res += buffer;
        pclose(fp);
        return res;
    }

    std::string RecvCommand() {
        char command[1024];
        ssize_t n = recv(_sockfd, command, sizeof(command) - 1, 0);
        if(n > 0) {
            command[n] = 0;
            return command;
        }
        else return std::string();
    }

    void SendCommand(std::string res) {
        if(res.empty()) res = "Empty";
        send(_sockfd, res.c_str(), res.size(), 0);
    }
private:
    int _sockfd;
    std::string _command;
    std::unordered_set<std::string> _hash_com;
};
cpp 复制代码
// TcpServer.hpp

#pragma once

#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/wait.h>
#include <pthread.h>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"
#include "ThreadPool.hpp"
#include "Command.hpp"

using namespace LogModule;

const static int default_backlog = 6;
const static int default_listenfd = -1;

class TcpServer : public nocopy
{
public:
    TcpServer(uint16_t port, int backlog = default_backlog)
    :_port(port), _listenfd(default_listenfd), _backlog(default_backlog), _running(false){}

    void Init() {
        // 创建socket
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd < 0) {
            LOG(LogLevel::ERROR) << "create socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogLevel::INFO) << "create socket success, sockfd: " << _listenfd;

        // bind
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);

        ssize_t n = bind(_listenfd, CONV(&local), sizeof(local));
        if(n < 0) {
            LOG(LogLevel::ERROR) << "socket bind error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Bind_Err);
        }
        LOG(LogLevel::INFO) << "bind socket success!!!";

        // 设置 socket 为监听状态
        n = listen(_listenfd, _backlog);
        if(n < 0) {
            LOG(LogLevel::ERROR) << "listen socket error, errno: " << errno << ", error string: " << strerror(errno);
            exit(Listen_Err);
        }
        LOG(LogLevel::INFO) << "listen socket success!!!";
    }

    void Start() {
        using task_t = std::function<void()>;
        _running = true;
        while(_running) {
            // 获取连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, CONV(&peer), &len);
            if(sockfd < 0) {
                LOG(LogLevel::WARNING) << "accept socket error, errno: " << errno << ", error string: " << strerror(errno);
                continue;
            }
            LOG(LogLevel::INFO) << "accept socket success, sockfd: " << sockfd;

            task_t t = std::bind(&TcpServer::Server, sockfd);
            ThreadPool<task_t>::GetInstance()->Push(t);
        }
    }

    static void Server(int sockfd) {
        while(true) {
            Command com(sockfd);
            std::string req = com.RecvCommand();
            if(req.empty()) break;
            std::string resp = com.Excute(req);
            com.SendCommand(resp);
        }
        // char buffer[4096];
        // // 一直进行IO操作
        // while(true) {
        //     // 可以使用文件的读写接口直接进行通信
        //     ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
        //     if(n > 0) {
        //         buffer[n] = 0;
        //         std::cout << "client say# " << buffer << std::endl;

        //         std::string echo = "server echo# ";
        //         echo += buffer;
        //         write(sockfd, echo.c_str(), echo.size());
        //     }
        //     else if(n == 0) { // 说明读到结尾,关闭连接
        //         LOG(LogLevel::INFO) << "client quit...";
        //         break;
        //     }
        //     else { // 文件读取出现错误
        //         LOG(LogLevel::ERROR) << "read sockfd error, errno: " << errno << ", error string: " << strerror(errno);
        //         break;
        //     }
        // }
    }
private:
    uint16_t _port;
    int _listenfd;
    int _backlog;
    bool _running;
};
相关推荐
智星云算力5 小时前
Ubuntu 25.10 “Questing Quokka” 版本解析
服务器·gpu算力·一体机·智星云·ai工作站
TG_yunshuguoji6 小时前
阿里云代理商:阿里云负载均衡是什么?
运维·服务器·阿里云·云计算
第二层皮-合肥6 小时前
如何设置等长的最大走线长度
服务器·开发语言·php
wifi chicken6 小时前
Linux 网络协议栈数据流跟踪-静态路由demo
linux·网络协议栈·静态路由
white-persist6 小时前
什么是网络安全,网络空间安全有哪些安全?
服务器·网络·安全·web安全·网络安全·系统安全·安全架构
程序员的世界你不懂6 小时前
【Linux】Centos替代方案
linux
剑小麟6 小时前
windows系统安装wls/Ubuntu子系统教程
linux·运维·ubuntu
Ronin3056 小时前
【Linux网络】应用层自定义协议
linux·网络·应用层·序列化
wanhengidc7 小时前
云手机和云游戏的不同之处
运维·服务器·安全·游戏·智能手机