Socket通信(C++)
文章目录
- 什么是Socket
- Socket通信过程
- C++ Socket通信API
- int socket(int domain, int type, int protocol);
- int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- struct sockaddr
- struct sockaddr_un
- struct sockaddr_in / struct sockaddr_in6
- int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- int listen(int sockfd, int backlog);
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- ssize_t send(int sockfd, const void *buf, size_t len, int flags);
- ssize_t recv(int sockfd, void *buf, size_t len, int flags);
- int close(int fd);
- C++ Socket通信
- 服务端
- 客户端
- C++ Socket通信改进
- UNIX socket文件已存在
- 子线程通信
- Socket通信流程改进
- 服务端
- 核心代码
- 头文件
- 全代码
- 客户端
什么是Socket
Socket是用于计算机之间进行网络通信的端口的抽象。提供了应用进程利用底层网络协议交换数据的机制。
通过TCP/IP协议栈进行网络通信的过程中,每个设备都需要唯一的IP地址信息进行标识,Socket允许应用程序通过IP地址进行通信,而不需要关心底层TCP/IP协议的具体实现,在这个过程中,可以将Socket理解为对TCP/IP的进一步封装。
同时,Socket也可以在本地进程之间通信,Socket允许应用绑定本地Socket文件,通过Socket文件进行进程之间数据的交换。
Socket通信过程

- 服务端:
- 创建Socket
- 绑定Socket: Socket支持绑定本地Socket或者IP端口
- 服务端开始监听客户端连接请求,当监听到连接请求后,调用accept()接收连接请求,建立服务端客户端连接
- 服务端客户端开始通信
- send(): 通过send接口发送数据
- receive(): 通过receive接口接收数据
- 服务端客户端处理通信异常信息
- 服务端主动关闭连接,或监听到客户端异常断开后,关闭连接
- 客户端:
- 创建Socket
- 请求连接服务端Socket
- 服务端客户端开始通信
- send(): 通过send接口发送数据
- receive(): 通过receive接口接收数据
- 服务端客户端处理通信异常信息
- 客户端主动关闭连接,或监听到服务端异常断开后,关闭连接
C++ Socket通信API
C++在进行Socket通信时,通常有以下常用接口:
int socket(int domain, int type, int protocol);
以下参数信息为常用参数信息,更多内容参考
man socket
- int socket(int domain, int type, int protocol):用于创建Socket
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- domain:网络连接协议簇的标识
- AF_INET:IPv4协议簇
- AF_INET6:IPv6协议簇
- AF_UNIX/AF_LOCAL:本地Socket
- type:Socket通信的语义类型
- SOCK_STREAM:提供有序、可靠、双向、基于连接的字节流。可以支持带外数据传输机制(TCP通信常用)
- SOCK_DGRAM:支持数据报(固定最大长度的无连接、不可靠的消息)(UDP通信常用)。
- protocol:与Socket通信语义相匹配的协议类型,注意,protocol的选择需要和语义类型匹配,不可以随意组合
- 0:根据type自动匹配protocol
- IPPROTO_TCP:TCP协议
- IPPROTO_UDP:UDP协议
- domain:网络连接协议簇的标识
- 返回值:
- 成功:返回Socket文件描述符ID
- 失败:返回-1,并设置errno
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen):socket()创建socket指定其协议类型后,我们还需要把socket绑定到具体的地址上才可以使用
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:上述通过
socket()函数创建的socketID信息 - addr:socket绑定的协议地址,该参数需要与socket创建时指定的协议类型相关联
- addrlen:addr结构的字节大小
- sockfd:上述通过
- 返回值:
- 成功:返回0
- 失败:返回-1,并设置errno
struct sockaddr
#include <sys/types.h>
#include <sys/socket.h>struct sockaddr {sa_family_t sa_family; // socket addr familychar sa_data[14]; // socket addr data
}
在sockaddr结构体中,数据信息混合在了一起,针对TCP/UDP这种包含IP和Port等多个数据的类型时,不是很好区分,所以一般情况下通过定义对应协议的addr信息,然后通过类型转换为soctaddr结构体
struct sockaddr_un
#include <sys/socket.h>
#include <sys/un.h>struct sockaddr_un {sa_family_t sun_family; // AF_UNIXchar sun_path[108]; // 本地Socket路径
};
struct sockaddr_in / struct sockaddr_in6
#include <netinet/in.h>struct sockaddr_in {sa_family_t sin_family; // AF_INETin_port_t sin_port; // Port: 端口号struct in_addr sin_addr; // IPv4地址信息
};struct sockaddr_in6 {sa_family_t sin6_family; // AF_INET6in_port_t sin6_port; // Port: 端口号uint32_t sin6_flowinfo; // IPv6流标识符,用于标识特定的数据流,在发送数据时附加到数据包头部struct in6_addr sin6_addr; // IPv6地址信息uint32_t sin6_scope_id; // Scope Id:用于确定IPv6地址的使用范围和权限
};
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen):客户端向服务端发送连接请求,等待连接
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:上述通过
socket()函数创建的socketID信息,该sockfd为客户端向服务端发起请求的socket - addr:socket绑定的协议地址,该参数需要与socket创建时指定的协议类型相关联
- addrlen:addr结构的字节大小
- sockfd:上述通过
- 返回值:
- 成功:返回0
- 失败:返回-1,并设置errno
int listen(int sockfd, int backlog);
- int listen(int sockfd, int backlog):设置socket队列,监听socket请求,以处理客户端的连接、断开操作
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:上述通过
socket()函数创建的socketID信息 - backlog: socket监听可能的最大连接长度,若队列已满,新的客户端连接请求会收到
ECONNREFUSED错误
- sockfd:上述通过
- 返回值:
- 成功:返回0
- 失败:返回-1,并设置errno
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen):监听sockfd队列的第一个连接请求,创建连接socket,并返回引用该socket的文件描述符
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:上述通过
socket()函数创建的socketID信息,该sockfd为客户端向服务端发起请求的socket - addr:socket绑定的协议地址,该参数需要与socket创建时指定的协议类型相关联
- addrlen:addr结构的字节大小
- sockfd:上述通过
- 返回值:
- 成功:返回socket文件描述符ID
- 失败:返回-1,并设置errno
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
socket 数据的常用发送接收还有
read(),write()和其他方法。
read()和write()方法在遇到\0类型数据时会终止,所以通过该方法发送数据是受限的,这里不做介绍
- ssize_t send(int sockfd, const void *buf, size_t len, int flags):发送指定长度的数据
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:客户端和服务端已建立的socketID文件描述符信息
- buf:需要发送的数据内容
- len: buffer数据长度
- flags: 消息发送或运算的特性,默认可为0
- 返回值:
- 成功:成功发送数据的字节数
- 失败:返回-1,并设置errno
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
- ssize_t recv(int sockfd, void *buf, size_t len, int flags):接收指定长度的数据
- 头文件:
- #include <sys/types.h>
- #include <sys/socket.h>
- 参数:
- sockfd:客户端和服务端已建立的socketID文件描述符信息
- buf:接收数据的地址
- len: buffer数据长度
- flags: 消息接收或运算的特性,默认可为0
- 返回值:
- 成功:成功发送数据的字节数
- 失败:返回-1,并设置errno
int close(int fd);
- int close(int fd):关闭socket连接
- 头文件:
- #include <unistd.h>
- 参数:
- fd:已连接的文件描述符ID
- 返回值:
- 成功:0
- 失败:返回-1,并设置errno
C++ Socket通信
若要使用IPv4-TCP通信,请注释UNIX,取消注释IPv4
本示例不对IPv6通信进行说明
服务端
// socket
#include <sys/types.h>
#include <sys/socket.h>// socket addr
#include <sys/un.h>
#include <netinet/in.h>// file close
#include <unistd.h>// htons
#include <arpa/inet.h>#include <iostream>int main() {// 1. 创建服务端Socket// IPv4// int server_socket = socket(AF_INET, SOCK_STREAM, 0);// UNIXint server_socket = socket(AF_UNIX, SOCK_STREAM, 0);if (server_socket < 0) {std::cerr << "socket error: 创建失败" << std::endl;throw std::runtime_error("socket error: 创建失败");} else {std::cout << "socket 创建成功,socketId:" << server_socket << std::endl;}// 2. 绑定Socket// IPv4// struct sockaddr_in server_addr;// server_addr.sin_family = AF_INET;// // INADDR_ANY: 0.0.0.0(绑定到本机的所有网卡上)// server_addr.sin_addr.s_addr = INADDR_ANY;// // htons: 将 unsigned short 转换为网络字节序// server_addr.sin_port = htons(8888);// UNIXstruct sockaddr_un server_addr;server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, "/var/tmp/socket_test");if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {std::cerr << "socket bind error: 绑定套接字失败,请检查本地套接字是否被占用" << std::endl;throw std::runtime_error("socket bind error: 绑定套接字失败,请检查本地套接字是否被占用");}// 3. 创建socket监听队列,并开始监听int listen_ret = listen(server_socket, 2048);if (listen_ret < 0) {std::cerr << "socket listen error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");} // 4. 接收客户端连接请求// IPv4// struct sockaddr_in client_addr;// UNIXstruct sockaddr_un client_addr;int client_addr_len = sizeof(client_addr);int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, (socklen_t *) &client_addr_len);if (client_socket < 0) {std::cerr << "socket client accpet error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");}// 5. 接收客户端发送信息int recv_data_length = 15;char recv_data[recv_data_length];if (recv(client_socket, recv_data, recv_data_length, 0) < 0) {std::cerr << "socket recv error: 接收数据失败" << std::endl;throw std::runtime_error("socket recv error: 接收数据失败");} else {std::cout << "socket recv data: " << recv_data << std::endl;}// 6. 关闭socketclose(server_socket);close(client_socket);return 0;
}
客户端
// socket
#include <sys/types.h>
#include <sys/socket.h>// socket addr
#include <sys/un.h>
#include <netinet/in.h>// file close
#include <unistd.h>// htons
#include <arpa/inet.h>#include <iostream>
#include <string.h>int main() {// 1. 创建客户端Socket// IPv4// int client_socket = socket(AF_INET, SOCK_STREAM, 0);// UNIXint client_socket = socket(AF_UNIX, SOCK_STREAM, 0);if (client_socket < 0) {std::cerr << "socket error: 创建失败" << std::endl;throw std::runtime_error("socket error: 创建失败");} else {std::cout << "socket 创建成功,socketId:" << client_socket << std::endl;}// 2. 绑定Socket// IPv4// struct sockaddr_in client_addr;// client_addr.sin_family = AF_INET;// // INADDR_ANY: 0.0.0.0(绑定到本机的所有网卡上)// client_addr.sin_addr.s_addr = INADDR_ANY;// // htons: 将 unsigned short 转换为网络字节序// client_addr.sin_port = htons(8888);// UNIXstruct sockaddr_un client_addr;client_addr.sun_family = AF_UNIX;strcpy(client_addr.sun_path, "/var/tmp/socket_test");if (connect(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0) {std::cerr << "socket connect error: 连接服务端socket失败" << std::endl;throw std::runtime_error("socket connect error: 连接服务端socket失败");}// 3. 客户端发送信息std::string send_data = "Hello, Focus!!!";if (send(client_socket, send_data.c_str(), send_data.length(), 0) < 0) {std::cerr << "socket send error: 发送数据失败" << std::endl;throw std::runtime_error("socket send error: 发送数据失败");} // 4. 关闭socketclose(client_socket);return 0;
}
C++ Socket通信改进
以上代码可以实现简单的Socket通信流程,但是存在问题:
- 服务端在第一次启动时,会创建本地Socket套接字文件,在以IP协议进行通信的Socket网络通信中,Socket关闭会释放端口,但是以UNIX本地Socket进行通信的Socket网络通信在关闭后,不会主动删除创建的Socket文件。在再次通信的过程中,会绑定失败
- 解决方案:在程序第一次绑定时,判断文件是否存在,存在则删除
- 在Socket通信过程中,
send,recv,accept,connect等函数为阻塞函数,所以一旦调用此类方法,程序阻塞,就不能接收其他连接和处理了- 解决方案1:采用非阻塞模型进行Socket通信
- 解决方案2:采用线程的方式,当新的socket连接建立后,将socket通信的过程放在线程中执行,线程结束释放该socket通信,这样可以通过
accept方法以阻塞的方式一直等待新的客户端连接 - 这里采用方案2进行改进
- Socket通信过程中,采用
send,recv方法虽然解决了write,read方法不能发送\0的问题,但是存在的问题是,通过send,recv传输数据需要已知数据大小,在数据大小确定的情况下,该方案很符合场景需要,但是在数据大小不确定的情况下。- 解决方案1: 确定"大"数据长度,数据长度不足后面补标志位、
- 解决方案2:在传输数据前,先发送数据大小,然后初始化buffer接收数据
- 这里采用方案2进行改进
在以下改进中,统一采用UNIX模型进行通信,IP模型请自行替换
UNIX socket文件已存在
#include <unistd.h>#include <iostream>
#include <string.h>void make_sure_socket_path(char *socket_path) {// F_OK:判断文件是否可读,若文件不存在则不可读if (access(socket_path, F_OK) == 0) {// unlink:删除文件if (unlink(socket_path) < 0) {std::cerr << "删除 socket:" << socket_path << " 失败" << std::endl;throw std::runtime_error("socket error: 创建失败");}}
}
子线程通信
头文件:
// socket
#include <sys/types.h>
#include <sys/socket.h>// socket addr
#include <sys/un.h>
#include <netinet/in.h>#include <pthread.h>#include <unistd.h>// htons
#include <arpa/inet.h>#include <iostream>class UnixSocketServer {private:std::string socket_path;// 记录服务端socket配置int socket_id;// 客户端最大连接数int max_client = 5;static void *thread_working(void *args);public:UnixSocketServer(std::string socket_path);~UnixSocketServer();void run();
};
#include "socket.h"UnixSocketServer::UnixSocketServer(std::string socket_path) {this->socket_path = socket_path;if (access(this->socket_path.c_str(), F_OK) == 0) {// unlink:删除文件if (unlink(this->socket_path.c_str()) < 0) {std::cerr << "删除 socket:" << this->socket_path << " 失败" << std::endl;throw std::runtime_error("socket error: 创建失败");}}// 1. 创建服务端socketthis->socket_id = socket(AF_UNIX, SOCK_STREAM, 0);if (this->socket_id < 0) {std::cerr << "socket error: 创建失败" << std::endl;throw std::runtime_error("socket error: 创建失败");} else {std::cout << "socket 创建成功,socketId:" << this->socket_id << std::endl;}// 2. 绑定Socketstruct sockaddr_un server_addr;server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, this->socket_path.c_str());if (bind(this->socket_id, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {std::cerr << "socket bind error: 绑定套接字失败,请检查本地套接字是否被占用" << std::endl;throw std::runtime_error("socket bind error: 绑定套接字失败,请检查本地套接字是否被占用");}// 3. 创建socket监听队列,并开始监听int listen_ret = listen(this->socket_id, this->max_client);if (listen_ret < 0) {std::cerr << "socket listen error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");}
}UnixSocketServer::~UnixSocketServer() {close(this->socket_id);unlink(this->socket_path.c_str());
}void *UnixSocketServer::thread_working(void *args) {}void UnixSocketServer::run() {while(true) {struct sockaddr_un client_addr;int client_addr_len = sizeof(client_addr);int client_id = accept(this->socket_id, (struct sockaddr*)&client_addr, (socklen_t *) &client_addr_len);if (client_id < 0) {std::cerr << "socket client accpet error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");} else {std::cout << "socket client accpet success: 客户端:" << client_id << "连接成功" << std::endl;}pthread_t thread_id = client_id;pthread_create(&thread_id, NULL, this->thread_working, (void *) &client_id);pthread_detach(thread_id);}
}int main() {UnixSocketServer *unixSocketServer = new UnixSocketServer("/var/tmp/socket_test");unixSocketServer->run();return 0;
}
Socket通信流程改进
服务端
核心代码
void *UnixSocketServer::thread_working(void *args) {int client_id = *(int *) args;while (true) {// 1. 接收数据长度// 注意这里不能采用 size_t 等类型定义,该类型会导致在不同架构编译器生成的 sizeof 大小不一致int receive_data_length;if (recv(client_id, &receive_data_length, sizeof(receive_data_length), 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据长度失败" << std::endl;break;} else {std::cout << "socket communication success: 客户端原始数据长度:" << receive_data_length << std::endl;}// 2. 接收数据char receive_data[receive_data_length];if (recv(client_id, &receive_data, receive_data_length, 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据失败" << std::endl;break;} else { // 这里通过 std::string 构造函数初始化接收数据// 接收数据长度没有 `\0`,C/C++在输出 char 时,遇到 `\0` 才会停止std::cout << "socket communication success: 客户端原始数据:" << std::string(receive_data, receive_data_length) << std::endl;}// 3. 发送数据长度std::string send_data = "Hello, Focus!!!";int send_data_length = send_data.length();if (send(client_id, &send_data_length, sizeof(send_data_length), 0) < 0) {std::cerr << "socket communication error: 发送客户端数据长度失败" << std::endl;break;}// 4. 发送数据if (send(client_id, send_data.c_str(), send_data_length, 0) < 0) {std::cerr << "socket communication error: 发送客户端数据失败" << std::endl;break;} }std::cout << "socket client close:客户端 " << client_id << " 已断开连接" << std::endl;close(client_id);
}
头文件
// socket
#include <sys/types.h>
#include <sys/socket.h>// socket addr
#include <sys/un.h>
#include <netinet/in.h>#include <pthread.h>#include <unistd.h>// htons
#include <arpa/inet.h>#include <iostream>class UnixSocketServer {private:std::string socket_path;// 记录服务端socket配置int socket_id;// 客户端最大连接数int max_client = 5;static void *thread_working(void *args);public:UnixSocketServer(std::string socket_path);~UnixSocketServer();void run();
};
全代码
#include "socket.h"UnixSocketServer::UnixSocketServer(std::string socket_path) {this->socket_path = socket_path;if (access(this->socket_path.c_str(), F_OK) == 0) {// unlink:删除文件if (unlink(this->socket_path.c_str()) < 0) {std::cerr << "删除 socket:" << this->socket_path << " 失败" << std::endl;throw std::runtime_error("socket error: 创建失败");}}// 1. 创建服务端socketthis->socket_id = socket(AF_UNIX, SOCK_STREAM, 0);if (this->socket_id < 0) {std::cerr << "socket error: 创建失败" << std::endl;throw std::runtime_error("socket error: 创建失败");} else {std::cout << "socket 创建成功,socketId:" << this->socket_id << std::endl;}// 2. 绑定Socketstruct sockaddr_un server_addr;server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, this->socket_path.c_str());if (bind(this->socket_id, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {std::cerr << "socket bind error: 绑定套接字失败,请检查本地套接字是否被占用" << std::endl;throw std::runtime_error("socket bind error: 绑定套接字失败,请检查本地套接字是否被占用");}// 3. 创建socket监听队列,并开始监听int listen_ret = listen(this->socket_id, this->max_client);if (listen_ret < 0) {std::cerr << "socket listen error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");}
}UnixSocketServer::~UnixSocketServer() {close(this->socket_id);unlink(this->socket_path.c_str());
}void *UnixSocketServer::thread_working(void *args) {int client_id = *(int *) args;while (true) {// 1. 接收数据长度// 注意这里不能采用 size_t 等类型定义,该类型会导致在不同架构编译器生成的 sizeof 大小不一致int receive_data_length;if (recv(client_id, &receive_data_length, sizeof(receive_data_length), 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据长度失败" << std::endl;break;} else {std::cout << "socket communication success: 客户端原始数据长度:" << receive_data_length << std::endl;}// 2. 接收数据char receive_data[receive_data_length];if (recv(client_id, &receive_data, receive_data_length, 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据失败" << std::endl;break;} else { // 这里通过 std::string 构造函数初始化接收数据// 接收数据长度没有 `\0`,C/C++在输出 char 时,遇到 `\0` 才会停止std::cout << "socket communication success: 客户端原始数据:" << std::string(receive_data, receive_data_length) << std::endl;}// 3. 发送数据长度std::string send_data = "Hello, Focus!!!";int send_data_length = send_data.length();if (send(client_id, &send_data_length, sizeof(send_data_length), 0) < 0) {std::cerr << "socket communication error: 发送客户端数据长度失败" << std::endl;break;}// 4. 发送数据if (send(client_id, send_data.c_str(), send_data_length, 0) < 0) {std::cerr << "socket communication error: 发送客户端数据失败" << std::endl;break;} }std::cout << "socket client close:客户端 " << client_id << " 已断开连接" << std::endl;close(client_id);
}void UnixSocketServer::run() {while(true) {struct sockaddr_un client_addr;int client_addr_len = sizeof(client_addr);int client_id = accept(this->socket_id, (struct sockaddr*)&client_addr, (socklen_t *) &client_addr_len);if (client_id < 0) {std::cerr << "socket client accpet error: Socket监听失败" << std::endl;throw std::runtime_error("socket listen error: Socket监听失败");} else {std::cout << "socket client accpet success: 客户端:" << client_id << "连接成功" << std::endl;}pthread_t thread_id = client_id;pthread_create(&thread_id, NULL, this->thread_working, (void *) &client_id);pthread_detach(thread_id);}
}int main() {UnixSocketServer *unixSocketServer = new UnixSocketServer("/var/tmp/socket_test");unixSocketServer->run();return 0;
}
客户端
// socket
#include <sys/types.h>
#include <sys/socket.h>// socket addr
#include <sys/un.h>
#include <netinet/in.h>// file close
#include <unistd.h>// htons
#include <arpa/inet.h>#include <iostream>
#include <string.h>int socket_connect(const char *socket_path) {// 1. 创建客户端Socketint client_socket = socket(AF_UNIX, SOCK_STREAM, 0);if (client_socket < 0) {std::cerr << "socket error: 创建失败" << std::endl;throw std::runtime_error("socket error: 创建失败");} else {std::cout << "socket 创建成功,socketId:" << client_socket << std::endl;}// 2. 绑定Socketstruct sockaddr_un client_addr;client_addr.sun_family = AF_UNIX;strcpy(client_addr.sun_path, socket_path);if (connect(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0) {std::cerr << "socket connect error: 连接服务端socket失败" << std::endl;throw std::runtime_error("socket connect error: 连接服务端socket失败");}return client_socket;
}int socket_close(int client_socket) {close(client_socket);
}void socket_communication(const char *socket_path, std::string send_data) {int client_socket = socket_connect(socket_path);// 1. 发送数据长度int send_data_length = send_data.length();if (send(client_socket, &send_data_length, sizeof(send_data_length), 0) < 0) {std::cerr << "socket communication error: 发送客户端数据长度失败" << std::endl;}// 2. 发送数据if (send(client_socket, send_data.c_str(), send_data_length, 0) < 0) {std::cerr << "socket communication error: 发送客户端数据失败" << std::endl;} // 3. 接收数据长度int receive_data_length;if (recv(client_socket, &receive_data_length, sizeof(receive_data_length), 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据长度失败" << std::endl;} else {std::cout << "socket communication success: 客户端原始数据长度:" << receive_data_length << std::endl;}// 2. 接收数据char receive_data[receive_data_length];if (recv(client_socket, &receive_data, receive_data_length, 0) <= 0) {std::cerr << "socket communication error: 接收客户端数据失败" << std::endl;} else {std::cout << "socket communication success: 客户端原始数据:" << receive_data << std::endl;}socket_close(client_socket);
}int main() {std::string data = R"({"args":null,"function":"select_all_algorithm_log","module":"dal","package":"log"})";socket_communication("/var/tmp/socket_test", data);return 0;
}
相关文章:
Socket通信(C++)
文章目录 什么是SocketSocket通信过程C Socket通信APIint socket(int domain, int type, int protocol);int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);struct sockaddrstruct sockaddr_unstruct sockaddr_in / struct sockaddr_in6 int connect(int …...
小白学大模型:LLaMA-Factory 介绍与使用
最近这一两周看到不少互联网公司都已经开始秋招提前批了。 不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC 在变少,岗位要求还更高了。 最近,我们又陆续整理了很多大厂的面试题,帮助一些球友…...
java算法day26
java算法day26 207 课程表208 实现Trie(前缀树) 207 课程表 这题对应的知识是图论里的拓扑排序的知识。从题意就可以感受出来了。题目说如果要学习某课程,那么就需要先完成某课程。 这里我描述比较复杂的情况:课程与课程之间也有可能是多对一的场景或者…...
docker笔记7-dockerfile
docker笔记7-dockerfile 一、dockerfile介绍二、dockerfile指令三、构建自己的镜像 一、dockerfile介绍 Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。 以下是常用的 Dockerfile 关键字的完整列表和说明: 二、docker…...
Spring-cloud Alibaba组件--Dubbo
远程调用技术 RestFul风格 基于HTTP协议实现,而HTTP是一种网络传输协议,基于TCP,规定了数据传输的格式。 RPC协议 Remote Produce Call 远程过程调用,类似的还有 RMI ( remote method invoke)。自定义数…...
右值引用--C++11
左值引用和右值引用 传统的C语法中就有引用的语法,而C11中新增了的右值引用语法特性,所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。 什么是左值?什么是左值引用?…...
这样做外贸报价表,客户看了才想下单
报价,是外贸业务中最重要的一步,作为外贸人,不会做报价表可不行。有人说,直接在邮件里回复价格不就好了?是的,产品简单的可以这么做,但你也不能忽视报价表的价值,一份完美的价格表对…...
Swift学习入门,新手小白看过来
😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。 😊 座右铭:不…...
【Ant Design Pro】快速上手
初始化 初始化脚手架:快速开始 官方默认使用 umi4,这里文档还没有及时更新(不能像文档一样选择 umi 的版本),之后我选择 simple。 然后安装依赖。 在 package.json 中: "start": "cross-e…...
Hive3:Hive初体验
1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …...
blender顶点乱飞的问题解决
初学blender,编辑模式下移动某些顶点,不管是移动还是滑动都会出现定点乱飞的问题,后来才发现是开了吸附工具的原因!!!! 像下面这样,其实我只是在Z轴上移动,但是就跑的很…...
Elasticsearch(ES) 集群脑裂
脑裂问题(split-brain problem)是指一个分布式系统中,当网络分裂(network partition)发生时,导致系统内部的两个或多个节点相互独立地认为自己仍然与其他节点连接,每个节点组都试图执行操作,这可能会导致数…...
spark 3.0.0源码环境搭建
环境 Spark版本:3.0.0 java版本:1.8 scala版本:2.12.19 Maven版本:3.8.1 编译spark 将spark-3.0.0的源码导入到idea中 执行mvn clean package -Phive -Phive-thriftserver -Pyarn -DskipTests 执行sparksql示例类SparkSQLExam…...
3.3、matlab彩色图和灰度图的二值化算法汇总
1、彩色图和灰度图的二值化算法汇总原理及流程 彩色图和灰度图的二值化算法的原理都是将图像中的像素值转化为二值(0或1),以便对图像进行简化或者特定的图像处理操作。下面分别介绍彩色图和灰度图的二值化算法的原理及流程: 1)彩色图的二值化算法原理及流程 (1)原理:…...
新手必看:Elasticsearch 入门全指南
Elasticsearch 入门介绍 Elasticsearch 是一个开源的分布式搜索和分析引擎,广泛应用于处理大规模数据和实时搜索需求。它基于 Apache Lucene 构建,具备高可扩展性和分布式特性,能够快速、可靠地存储、搜索和分析大量数据。本文将介绍 Elasti…...
【Linux】TCP全解析:构建可靠的网络通信桥梁
文章目录 前言1. TCP 协议概述2. TCP报头结构3. 如何理解封装和解包呢?4. TCP的可靠性机制4.1 TCP的确认应答机制4.2 超时重传机制 5. TCP链接管理机制5.1 经典面试题:为什么建立连接是三次握手?5.2 经典面试题:为什么要进行四次挥…...
图像处理 -- ISP中的3DNR与2DNR区别及实现原理
ISP中的3DNR与2DNR区别及实现原理 2DNR(2D Noise Reduction) 2DNR的原理: 2DNR主要针对单帧图像进行降噪处理。它利用空间域内的像素值,采用空间滤波的方法来减少噪声。常用的方法包括均值滤波、中值滤波和高斯滤波等。这些方法…...
硬盘分区读不出来的解决之道:从自救到专业恢复
在日常的计算机使用过程中,硬盘分区读不出来的问题常常令人头疼不已。这一问题不仅阻碍了用户对数据的正常访问,还可能预示着数据安全的潜在威胁。硬盘分区读不出来,通常是由于分区表损坏、文件系统错误、物理扇区损坏、驱动程序冲突或硬件连…...
盘点2024年网上很火的4个语音识别转文字工具。
语音识别转文字是一项非常实用的技术,可以帮助我们在会议记录中省去手动记录,在采访中迅速得到文字稿,在学习中快速生成课堂笔...运用十分广泛。但是很多人不知道要怎么转换,在这里我便给大家介绍几款效率非常高的语音转文字的工具…...
解决 Git 访问 GitHub 时的 SSL 错误
引言 在使用 Git 进行版本控制时,我们可能会遇到各种网络相关的错误。其中一种常见的错误是 SSL 连接问题,这会导致 Git 无法访问远程仓库。本文将介绍一个具体的错误 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0,以及如何通过禁用 SSL 证…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
