概要
当第一次运行服务端时正常,第二次运行时出现Bind failed问题。
在实际使用中,如果您尝试启动一个服务端程序并且遇到了 “Bind failed” 的错误信息,这通常意味着尝试绑定(bind)的端口已经被占用。这种情况可能有以下几个常见原因:
-
端口占用:如果之前启动的服务端实例没有正确关闭,或者其他程序正在使用相同的端口,那么操作系统将不允许您再次绑定到该端口。
-
未正确释放端口:在服务端程序异常退出或者没有正确关闭套接字的情况下,操作系统可能仍然认为端口正在被使用。
-
TIME_WAIT状态:即使服务端正确关闭了套接字,TCP端口可能会因为TIME_WAIT状态而暂时不可用。TIME_WAIT是TCP连接正常关闭后的一个保留状态,用于确保所有的数据包都正确地完成传输。这个状态通常会持续一段时间(通常是几分钟)。
-
系统安全策略:某些操作系统可能有安全策略限制了对低端口号(通常是1024以下)的访问。这通常会要求服务端程序以管理员或特权用户身份运行。
为了解决 “Bind failed” 的问题,您可以采取以下几个步骤:
-
检查端口使用情况:在Unix-like系统中,可以使用 lsof -i :端口号 或 netstat -tulnp | grep 端口号 命令来检查端口占用情况。在Windows系统中,可以使用 netstat -aon | findstr 端口号。
-
确保正确关闭套接字:在您的代码中,确保在服务端关闭时,您调用了套接字的关闭方法。
-
设置SO_REUSEADDR套接字选项:这个选项允许重新绑定到正在TIME_WAIT状态的端口。在C/C++中,这可以通过设置套接字选项来完成:
int yes = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
// 错误处理
-
更改端口号:尝试使用另一个未被占用的端口号。
-
检查权限:确保您的程序有足够的权限来绑定所需的端口。
-
重启系统:如果以上方法都无法解决问题,重启系统可以清除所有占用的端口,并重置网络堆栈。
样例代码
头文件文章来源:https://www.toymoban.com/news/detail-856312.html
#include <ros/ros.h>
#include "std_msgs/String.h"
#include "std_msgs/Bool.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "geometry_msgs/Twist.h"
#include <thread>
using namespace std;
class TCPPublisher
{
public:
TCPPublisher();
~TCPPublisher();
void cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg);
void acceptClients();
void sendToAllClients(const std::string& message);
private:
ros::NodeHandle n, nPrivate;
ros::Publisher tcpPub;
ros::Subscriber cmdVelSub;
// 创建服务器套接字
int serverSocket;
// 设置服务器地址结构
sockaddr_in serverAddr;
std::vector<int> clientSockets;
std::mutex clientSocketsMutex;
int clientSocket;
std::string topicStatus;
std::thread acceptThread;
};
main.cpp文章来源地址https://www.toymoban.com/news/detail-856312.html
#include "./tcp_pub/tcp_pub.h"
TCPPublisher::TCPPublisher():nPrivate("~")
{
nPrivate.param("topicStatus", topicStatus, std::string("/cmd_vel"));
// 创建套接字
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
// 设置套接字选项,允许重新使用本地地址和端口
int yes = 1;
if (setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
std::cerr << "Setsockopt failed." << std::endl;
close(serverSocket);
return;
}
/*订阅话题*/
cmdVelSub = n.subscribe(topicStatus.c_str(), 10, &TCPPublisher::cmdVelCallback, this);
// 设置服务器地址结构
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080); // 服务器监听的端口号
// 绑定套接字
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
std::cerr << "Bind failed." << std::endl;
close(serverSocket);
return;
}
// 监听连接
if (listen(serverSocket, SOMAXCONN) == -1) {
std::cerr << "Listen failed." << std::endl;
close(serverSocket);
return;
}
std::cout << "Server is listening for incoming connections..." << std::endl;
// 在新线程中接受客户端连接
acceptThread = std::thread(&TCPPublisher::acceptClients, this);
ROS_INFO("TCPPublisher init successfully!!!");
}
TCPPublisher::~TCPPublisher()
{
close(serverSocket);
}
void TCPPublisher::cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg)
{
float velX = msg->linear.x;
float angularZ = msg->angular.z;
// ROS_INFO("velX : %f, angularZ : %f", velX, angularZ);
// 定义字符数组,用于存储转换后的结果
char buffer[50]; // 适当调整数组大小以适应你的需求
snprintf(buffer, sizeof(buffer), "%f,%f", velX, angularZ);
// ROS_INFO("buffer %s", buffer);
std::ostringstream ss;
ss << velX << "," << angularZ;
sendToAllClients(ss.str());
}
void TCPPublisher::acceptClients() {
while (ros::ok()) {
int clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket == -1) {
std::cerr << "Accept failed." << std::endl;
continue;
}
std::cout << "Connection established with a client." << std::endl;
// 添加到客户端列表
std::lock_guard<std::mutex> guard(clientSocketsMutex);
clientSockets.push_back(clientSocket);
}
}
void TCPPublisher::sendToAllClients(const std::string& message) {
std::lock_guard<std::mutex> guard(clientSocketsMutex);
for (auto it = clientSockets.begin(); it != clientSockets.end(); ) {
if (send(*it, message.c_str(), message.size(), 0) == -1) {
std::cerr << "Error sending message to client." << std::endl;
close(*it);
it = clientSockets.erase(it); // Remove from list if send fails
} else {
++it;
}
}
}
int main(int argc, char **argv) {
//创建节点
ros::init(argc, argv, "pure_pursuit");
TCPPublisher tp;
ros::spin();
return 0;
}
到了这里,关于解决TCP中Bind failed烦恼的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!