TCP/IP 网络编程 | 服务端 客户端的封装
设计模式
文章目录
- 设计模式
- 一、`socket.h` 接口(interface)
- 二、`socket.cpp` 实现(implementation)
- 三、`server.cpp` 使用封装(main 函数)
- 四、`client.cpp` 使用封装(main 函数)
- 五、退出方法
- 六、终端输出
一、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> // memsetint 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;
}
五、退出方法
- 客户端:
当你在客户端输入:
Enter message: exit
客户端程序会退出(break
出循环)。
- 服务器:
- 当前版本是永不退出的死循环
- 你可以使用
Ctrl+C
来中断服务器进程
六、终端输出
- 终端 1:服务器
$ ./server
Server listening on port 8888...
Received: hello
Received: world
- 终端 2:客户端
$ ./client
Connected to server.
Enter message: hello
Server response: Echo: helloEnter message: world
Server response: Echo: worldEnter message: exit