如何将C++ Socket客户端服务器程序改写为支持长尾词查询的问答系统?

2026-04-12 05:042阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1975个文字,预计阅读时间需要8分钟。

如何将C++ Socket客户端/服务器程序改写为支持长尾词查询的问答系统?

当然可以。以下是对您提供的文本的简化修改:

虽然学习了TCP socket编程,但总是记不住。这里直接给出一个可用的+C+++TCP socket程序。使用cmake管理,但我是个半吊子水平。在学习过程中,例如参考CMake教程,程序结构PROG_HOME→build。

虽然学了很多回了,但总是记不住。 这里直接给个可以使用的 CPP TCP socket 程序吧。 使用cmake管理,但是我是个半吊子水平。在学习,例如CMake Tutorial

程序结构

PROG_HOME ├── build # 可以不自己创建,直接运行run.sh会给生成的。 ├── CMakeLists.txt # ├── docs # 好吧,我还没习惯写文档 ├── include # 实际上我并没用到include,我也不知道怎么去使用,cmake还在学习中。 ├── libs # 库文件 │   ├── CMakeLists.txt │   └── socket # 自己写的socket库 │   ├── CMakeLists.txt │   ├── socket.cpp │   └── socket.h ├── run.sh # 这个脚本用于简化编译运行步骤 └── src ├── client.cpp └── server.cpp

CMakeLists.txt文件

在这里有3个CMakeLists.txt。至于怎么管理的搞不太清楚的,需要先学习,我也是半吊子。

项目的CMakeLists.txt源码

cmake_minimum_required(VERSION 3.5) project(socket_test) set(CMAKE_CXX_STANDARD 11) # 虽然没有用到,还是给加进来了,主要是我也没有刻意区分了 include_directories(include) # 添加库文件 add_subdirectory(libs) # C/S可执行程序 add_executable(client ./src/client.cpp) add_executable(server ./src/server.cpp) # 链接socket库 target_link_libraries(client PUBLIC socket) target_link_libraries(server PUBLIC socket)

libs下的CMakeLists.txt源码

# 只需要加上需要的库(实际上也只有这一个) add_subdirectory(socket)

socket下的CMakeLists.txt源码

# 添加库 add_library(socket STATIC socket.cpp) # 添加引用文件,以便于让client和server引入(但是总感觉这样用怪怪的) target_include_directories(socket PUBLIC ".")

socket库

socket流程,在CPP和C中没有太大区别。大致流程如下,至于分析三次握手协议,不在这里说了。

如何将C++ Socket客户端/服务器程序改写为支持长尾词查询的问答系统?

  1. server:socket() => bind() => listen() => accept() => read/write => close()
  2. client: socket() [=> bind()] => connect() => read/write => close()

以下是一个阻塞型的TCP socket程序。 要改为非阻塞型或者UDP,就需要另外学习其他的了。

socket.h

/****************************************************** * File Name: socket.h * Author: basilguo@163.com * Created Time: 2023-08-13 09:15:29 * Description: socket库头文件,定义数据结构 ******************************************************/ #ifndef SOCKET_H #define SOCKET_H #include <string> using std::string; // 套两层,实际上在这里套不套都可以,反正是自己写的,只是为了代码隔离。 // 但是貌似无所谓了,套吧 namespace basil { namespace socket { class Socket { public: Socket(); Socket(int sockfd); ~Socket(); // 把socket程序的基础函数都拿过来了 bool bind(const string &ip, const int port); bool listen(const int backlog); bool connect(const string &ip, const int port); int accept(); int send(const char *buf, int len); int recv(char *buf, int len); void close(); private: string m_ip; int m_port; int m_sockfd; }; } } #endif // SOCKET_H

socket.cpp

/***************************************************** * File Name: socket.cpp * Author: basilguo@163.com * Created Time: 2023-08-13 09:18:11 * Description: 实现。应该使用日志文件,但是我没写,简单点就直接打印吧。 ******************************************************/ #include <iostream> #include <string> #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace std; using namespace basil::socket; /* 创建socket */ Socket::Socket() : m_ip(""), m_port(0), m_sockfd(-1) { m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_sockfd < 0) { perror("socket()"); return; } printf("socket() create successfully!\n"); } /* 创建socket,用于server的接收 */ Socket::Socket(int sockfd) : m_ip (""), m_port(0), m_sockfd(sockfd) {} /* 销毁socket,就是关闭 */ Socket::~Socket() { close(); } /* 绑定 */ bool Socket::bind(const string &ip, const int port) { struct sockaddr_in sockaddr; if (ip.empty()) { sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); } else { sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); } sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); if (::bind(m_sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { perror("bind()"); return false; } m_ip = ip; m_port = port; printf("bind() successfully\n"); return true; } /* 监听 */ bool Socket::listen(const int backlog) { if (::listen(m_sockfd, backlog) < 0) { perror("listen()"); return false; } printf("listen() at [%s:%d] successfully\n", m_ip.c_str(), m_port); return true; } /* client主动连接 */ bool Socket::connect(const string &ip, const int port) { struct sockaddr_in sockaddr; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); if (::connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(struct sockaddr)) < 0) { perror("connect()"); return false; } printf("connect() successfully\n"); m_ip = ip; m_port = port; return true; } /* server等待连接 */ int Socket::accept() { int connfd = ::accept(m_sockfd, nullptr, nullptr); if (connfd < 0) { perror("accept()"); return -1; } printf("accept() successfully\n"); return connfd; } /* 发送 */ int Socket::send(const char *buf, int len) { return ::send(m_sockfd, buf, len, 0); } /* 接收 */ int Socket::recv(char *buf, int len) { return ::recv(m_sockfd, buf, len, 0); } /* 关闭socket */ void Socket::close() { if (m_sockfd > 0) { ::close(m_sockfd); m_sockfd = 0; } }

程序源码

客户端

/****************************************************** * File Name: src/client.cpp * Author: basilguo@163.com * Created Time: 2023-08-13 02:28:10 * Description: ******************************************************/ #include <string> #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace basil::socket; using std::string; int main(int argc, char *argv[]) { Socket client; bool connected = client.connect("127.0.0.1", 8008); if (!connected) { fprintf(stderr, "connected failed\n"); return -1; } string data; char buf[1024] = {0}; while (1) { printf("[C->S]: "); scanf("%s", buf); data = buf; client.send(data.c_str(), data.size()); if (strncmp(buf, "quit", 4) == 0) { printf("byebye~\n"); break; } client.recv(buf, 1024); printf("[S->C]: %s\n", buf); } return 0; }

服务端

/****************************************************** * File Name: server.cpp * Author: basilguo@163.com * Created Time: 2022-10-09 07:34:59 * Description: 使用CPP风格的socket,不要再使用C风格的socket。 ******************************************************/ #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace basil::socket; using std::string; int main() { Socket server; string ip = "127.0.0.1"; int port = 8008; server.bind(ip, port); server.listen(1024); while (true) { int connfd = server.accept(); if (connfd < 0) break; Socket client(connfd); while(true) { char buf[1024] = {0}; size_t len = client.recv(buf, sizeof(buf)); printf("[C->S]: %s\n", buf); if (strncmp(buf, "quit", 4) == 0) { bzero(buf, 1024); len = strlen("byebye~"); snprintf(buf, len, "byebye~"); client.send(buf, len); printf("[client: %d] byebye~\n", connfd); break; } client.send(buf, len); } client.close(); } server.close(); }

运行测试

#!/bin/bash mkdir -p build rm -rf build/* cd build cmake .. make if [ 0 -ne $# ] then ./$@ fi

  1. 起服务端

$ ./run.sh server -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/basil/code/cpp/server_dev/sockets/build [ 16%] Building CXX object libs/socket/CMakeFiles/socket.dir/socket.cpp.o [ 33%] Linking CXX static library libsocket.a [ 33%] Built target socket [ 50%] Building CXX object CMakeFiles/client.dir/src/client.cpp.o [ 66%] Linking CXX executable client [ 66%] Built target client [ 83%] Building CXX object CMakeFiles/server.dir/src/server.cpp.o [100%] Linking CXX executable server [100%] Built target server socket() create successfully! bind() successfully listen() at [127.0.0.1:8008] successfully

  1. 起客户端

$ ./run.sh client -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/basil/code/cpp/server_dev/sockets/build [ 16%] Building CXX object libs/socket/CMakeFiles/socket.dir/socket.cpp.o [ 33%] Linking CXX static library libsocket.a [ 33%] Built target socket [ 50%] Building CXX object CMakeFiles/client.dir/src/client.cpp.o [ 66%] Linking CXX executable client [ 66%] Built target client [ 83%] Building CXX object CMakeFiles/server.dir/src/server.cpp.o [100%] Linking CXX executable server [100%] Built target server socket() create successfully! connect() successfully [C->S]:

至于测试,就是在client输入,server输出以及返回。当client输入为quit时,就会退出client端,server端也会断开连接。如果不想自己写client,或者只是简单测试,其实可以使用nc 127.0.0.1 8008命令来测试,不过需要安装下ncat。

不过这里只能输入一些字符串,而不能输入int等其它类型(更多时候可能是二进制的)得再改改。

参考

  1. 高级篇---网络编程基础

本文共计1975个文字,预计阅读时间需要8分钟。

如何将C++ Socket客户端/服务器程序改写为支持长尾词查询的问答系统?

当然可以。以下是对您提供的文本的简化修改:

虽然学习了TCP socket编程,但总是记不住。这里直接给出一个可用的+C+++TCP socket程序。使用cmake管理,但我是个半吊子水平。在学习过程中,例如参考CMake教程,程序结构PROG_HOME→build。

虽然学了很多回了,但总是记不住。 这里直接给个可以使用的 CPP TCP socket 程序吧。 使用cmake管理,但是我是个半吊子水平。在学习,例如CMake Tutorial

程序结构

PROG_HOME ├── build # 可以不自己创建,直接运行run.sh会给生成的。 ├── CMakeLists.txt # ├── docs # 好吧,我还没习惯写文档 ├── include # 实际上我并没用到include,我也不知道怎么去使用,cmake还在学习中。 ├── libs # 库文件 │   ├── CMakeLists.txt │   └── socket # 自己写的socket库 │   ├── CMakeLists.txt │   ├── socket.cpp │   └── socket.h ├── run.sh # 这个脚本用于简化编译运行步骤 └── src ├── client.cpp └── server.cpp

CMakeLists.txt文件

在这里有3个CMakeLists.txt。至于怎么管理的搞不太清楚的,需要先学习,我也是半吊子。

项目的CMakeLists.txt源码

cmake_minimum_required(VERSION 3.5) project(socket_test) set(CMAKE_CXX_STANDARD 11) # 虽然没有用到,还是给加进来了,主要是我也没有刻意区分了 include_directories(include) # 添加库文件 add_subdirectory(libs) # C/S可执行程序 add_executable(client ./src/client.cpp) add_executable(server ./src/server.cpp) # 链接socket库 target_link_libraries(client PUBLIC socket) target_link_libraries(server PUBLIC socket)

libs下的CMakeLists.txt源码

# 只需要加上需要的库(实际上也只有这一个) add_subdirectory(socket)

socket下的CMakeLists.txt源码

# 添加库 add_library(socket STATIC socket.cpp) # 添加引用文件,以便于让client和server引入(但是总感觉这样用怪怪的) target_include_directories(socket PUBLIC ".")

socket库

socket流程,在CPP和C中没有太大区别。大致流程如下,至于分析三次握手协议,不在这里说了。

如何将C++ Socket客户端/服务器程序改写为支持长尾词查询的问答系统?

  1. server:socket() => bind() => listen() => accept() => read/write => close()
  2. client: socket() [=> bind()] => connect() => read/write => close()

以下是一个阻塞型的TCP socket程序。 要改为非阻塞型或者UDP,就需要另外学习其他的了。

socket.h

/****************************************************** * File Name: socket.h * Author: basilguo@163.com * Created Time: 2023-08-13 09:15:29 * Description: socket库头文件,定义数据结构 ******************************************************/ #ifndef SOCKET_H #define SOCKET_H #include <string> using std::string; // 套两层,实际上在这里套不套都可以,反正是自己写的,只是为了代码隔离。 // 但是貌似无所谓了,套吧 namespace basil { namespace socket { class Socket { public: Socket(); Socket(int sockfd); ~Socket(); // 把socket程序的基础函数都拿过来了 bool bind(const string &ip, const int port); bool listen(const int backlog); bool connect(const string &ip, const int port); int accept(); int send(const char *buf, int len); int recv(char *buf, int len); void close(); private: string m_ip; int m_port; int m_sockfd; }; } } #endif // SOCKET_H

socket.cpp

/***************************************************** * File Name: socket.cpp * Author: basilguo@163.com * Created Time: 2023-08-13 09:18:11 * Description: 实现。应该使用日志文件,但是我没写,简单点就直接打印吧。 ******************************************************/ #include <iostream> #include <string> #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace std; using namespace basil::socket; /* 创建socket */ Socket::Socket() : m_ip(""), m_port(0), m_sockfd(-1) { m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (m_sockfd < 0) { perror("socket()"); return; } printf("socket() create successfully!\n"); } /* 创建socket,用于server的接收 */ Socket::Socket(int sockfd) : m_ip (""), m_port(0), m_sockfd(sockfd) {} /* 销毁socket,就是关闭 */ Socket::~Socket() { close(); } /* 绑定 */ bool Socket::bind(const string &ip, const int port) { struct sockaddr_in sockaddr; if (ip.empty()) { sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); } else { sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); } sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); if (::bind(m_sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { perror("bind()"); return false; } m_ip = ip; m_port = port; printf("bind() successfully\n"); return true; } /* 监听 */ bool Socket::listen(const int backlog) { if (::listen(m_sockfd, backlog) < 0) { perror("listen()"); return false; } printf("listen() at [%s:%d] successfully\n", m_ip.c_str(), m_port); return true; } /* client主动连接 */ bool Socket::connect(const string &ip, const int port) { struct sockaddr_in sockaddr; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); if (::connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(struct sockaddr)) < 0) { perror("connect()"); return false; } printf("connect() successfully\n"); m_ip = ip; m_port = port; return true; } /* server等待连接 */ int Socket::accept() { int connfd = ::accept(m_sockfd, nullptr, nullptr); if (connfd < 0) { perror("accept()"); return -1; } printf("accept() successfully\n"); return connfd; } /* 发送 */ int Socket::send(const char *buf, int len) { return ::send(m_sockfd, buf, len, 0); } /* 接收 */ int Socket::recv(char *buf, int len) { return ::recv(m_sockfd, buf, len, 0); } /* 关闭socket */ void Socket::close() { if (m_sockfd > 0) { ::close(m_sockfd); m_sockfd = 0; } }

程序源码

客户端

/****************************************************** * File Name: src/client.cpp * Author: basilguo@163.com * Created Time: 2023-08-13 02:28:10 * Description: ******************************************************/ #include <string> #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace basil::socket; using std::string; int main(int argc, char *argv[]) { Socket client; bool connected = client.connect("127.0.0.1", 8008); if (!connected) { fprintf(stderr, "connected failed\n"); return -1; } string data; char buf[1024] = {0}; while (1) { printf("[C->S]: "); scanf("%s", buf); data = buf; client.send(data.c_str(), data.size()); if (strncmp(buf, "quit", 4) == 0) { printf("byebye~\n"); break; } client.recv(buf, 1024); printf("[S->C]: %s\n", buf); } return 0; }

服务端

/****************************************************** * File Name: server.cpp * Author: basilguo@163.com * Created Time: 2022-10-09 07:34:59 * Description: 使用CPP风格的socket,不要再使用C风格的socket。 ******************************************************/ #include <cstring> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include "socket.h" using namespace basil::socket; using std::string; int main() { Socket server; string ip = "127.0.0.1"; int port = 8008; server.bind(ip, port); server.listen(1024); while (true) { int connfd = server.accept(); if (connfd < 0) break; Socket client(connfd); while(true) { char buf[1024] = {0}; size_t len = client.recv(buf, sizeof(buf)); printf("[C->S]: %s\n", buf); if (strncmp(buf, "quit", 4) == 0) { bzero(buf, 1024); len = strlen("byebye~"); snprintf(buf, len, "byebye~"); client.send(buf, len); printf("[client: %d] byebye~\n", connfd); break; } client.send(buf, len); } client.close(); } server.close(); }

运行测试

#!/bin/bash mkdir -p build rm -rf build/* cd build cmake .. make if [ 0 -ne $# ] then ./$@ fi

  1. 起服务端

$ ./run.sh server -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/basil/code/cpp/server_dev/sockets/build [ 16%] Building CXX object libs/socket/CMakeFiles/socket.dir/socket.cpp.o [ 33%] Linking CXX static library libsocket.a [ 33%] Built target socket [ 50%] Building CXX object CMakeFiles/client.dir/src/client.cpp.o [ 66%] Linking CXX executable client [ 66%] Built target client [ 83%] Building CXX object CMakeFiles/server.dir/src/server.cpp.o [100%] Linking CXX executable server [100%] Built target server socket() create successfully! bind() successfully listen() at [127.0.0.1:8008] successfully

  1. 起客户端

$ ./run.sh client -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/basil/code/cpp/server_dev/sockets/build [ 16%] Building CXX object libs/socket/CMakeFiles/socket.dir/socket.cpp.o [ 33%] Linking CXX static library libsocket.a [ 33%] Built target socket [ 50%] Building CXX object CMakeFiles/client.dir/src/client.cpp.o [ 66%] Linking CXX executable client [ 66%] Built target client [ 83%] Building CXX object CMakeFiles/server.dir/src/server.cpp.o [100%] Linking CXX executable server [100%] Built target server socket() create successfully! connect() successfully [C->S]:

至于测试,就是在client输入,server输出以及返回。当client输入为quit时,就会退出client端,server端也会断开连接。如果不想自己写client,或者只是简单测试,其实可以使用nc 127.0.0.1 8008命令来测试,不过需要安装下ncat。

不过这里只能输入一些字符串,而不能输入int等其它类型(更多时候可能是二进制的)得再改改。

参考

  1. 高级篇---网络编程基础