TCP/IP 网络编程 | 服务端 & 客户端的封装

发布于:2025-06-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

设计模式

一、socket.h 接口(interface)

#ifndef SOCKET_H
#define SOCKET_H

#include <string>
using std::string;

class Socket
{
public:
    Socket();
    ~Socket();

    bool bind(int port);
    bool listen(int backlog = 5);
    int accept();

    bool connect(const string &ip, int port);  // ✅ 客户端连接方法

    int fd() const { return m_sockfd; } // 可选:暴露 sockfd 方便客户端用

private:
    int m_sockfd;
};

#endif // SOCKET_H

二、socket.cpp 实现(implementation)

// socket.cpp
#include "socket.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <cerrno>

using std::string;

Socket::Socket()
{
    m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (m_sockfd < 0)
    {
        printf("Socket creation failed: errno=%d, errmsg=%s\n", errno, strerror(errno));
    }
}

Socket::~Socket()
{
    if (m_sockfd >= 0)
    {
        ::close(m_sockfd);
    }
}

bool Socket::connect(const string &ip, int port)
{
    sockaddr_in addr;
    std::memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);

    if (::inet_pton(AF_INET, ip.c_str(), &addr.sin_addr) <= 0)
    {
        printf("Invalid IP address: %s\n", ip.c_str());
        return false;
    }

    int ret = ::connect(m_sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret < 0)
    {
        printf("Connect failed: errno=%d, errmsg=%s\n", errno, strerror(errno));
        return false;
    }

    return true;
}

void Socket::close()
{
    if (m_sockfd >= 0)
    {
        ::close(m_sockfd);
        m_sockfd = -1;
    }
}

三、server.cpp 使用封装(main 函数)

#include "socket.h"

#include <iostream>
#include <unistd.h>    // read(), write()
#include <cstring>     // memset

int main()
{
    Socket server;

    if (!server.bind(8888))
    {
        std::cerr << "Failed to bind port 8888" << std::endl;
        return 1;
    }

    if (!server.listen())
    {
        std::cerr << "Failed to listen on port 8888" << std::endl;
        return 1;
    }

    std::cout << "Server listening on port 8888..." << std::endl;

    while (true)
    {
        int client_fd = server.accept();
        if (client_fd < 0)
        {
            continue; // accept failed
        }

        char buffer[1024];
        ssize_t n = ::read(client_fd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << "Received: " << buffer << std::endl;

            std::string response = "Echo: ";
            response += buffer;
            ::write(client_fd, response.c_str(), response.size());
        }

        ::close(client_fd);
    }

    return 0;
}

四、client.cpp 使用封装(main 函数)

#include "socket.h"

#include <iostream>
#include <unistd.h>     // read(), write()
#include <cstring>      // strlen()

int main()
{
    Socket client;

    if (!client.connect("127.0.0.1", 8888))
    {
        std::cerr << "Failed to connect to server." << std::endl;
        return 1;
    }

    std::cout << "Connected to server." << std::endl;

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

        if (input == "exit")
            break;

        ::write(client.fd(), input.c_str(), input.size());

        char buffer[1024];
        ssize_t n = ::read(client.fd(), buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << "Server response: " << buffer << std::endl;
        }
        else
        {
            std::cout << "Server closed connection." << std::endl;
            break;
        }
    }

    return 0;
}

五、退出方法

  1. 客户端:
    当你在客户端输入:
Enter message: exit

客户端程序会退出(break 出循环)。

  1. 服务器:
    • 当前版本是永不退出的死循环
    • 你可以使用 Ctrl+C 来中断服务器进程

六、终端输出

  1. 终端 1:服务器
$ ./server
Server listening on port 8888...
Received: hello
Received: world
  1. 终端 2:客户端
$ ./client
Connected to server.
Enter message: hello
Server response: Echo: hello

Enter message: world
Server response: Echo: world

Enter message: exit

网站公告

今日签到

点亮在社区的每一天
去签到