解决TCP中Bind failed烦恼

这篇具有很好参考价值的文章主要介绍了解决TCP中Bind failed烦恼。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概要

当第一次运行服务端时正常,第二次运行时出现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) {
    // 错误处理
  • 更改端口号:尝试使用另一个未被占用的端口号。

  • 检查权限:确保您的程序有足够的权限来绑定所需的端口。

  • 重启系统:如果以上方法都无法解决问题,重启系统可以清除所有占用的端口,并重置网络堆栈。

样例代码

头文件

#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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决httpd占用80端口导致Nginx启动不成功报nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

            今天在建自己小网站时启动Nginx时,发现其报下列错误,意思是因为80端口被占用导致Nginx启动失败。           既然是因为80端口被占用了,那我们就要首先排查错误缘由,使用下面该命令对80端口进行摸排,结果显示80端口被httpd这个程序一直占用着。          

    2024年02月05日
    浏览(37)
  • linux下clash启动出现“server error: listen tcp 127.0.0.1:7890: bind: address already in use”的解决方法

    原因是端口被占用了,根据网上的解决方法,一说使用lsof查询占用端口的进程,再kill掉 另一说是手动更改clash的配置文件“config.yaml”,本人是使用这个方法解决的。 在这里不得不多说两句,clash的配置文件可能在这个目录下: 但是我在装clash时将配置文件放在了其他地方,

    2024年02月08日
    浏览(39)
  • creating server tcp listening socket 127.0.0.1:6379: bind No error

    window下启动redis服务报错: creating server tcp listening socket 127.0.0.1:6379: bind No error 解决方案如下按顺序输入如下命令即可连接成功 redis-cli.exe shutdown exit 运行:redis-server.exe redis.windows.conf shutdown出现以下错误,请exit退出 执行:D:devRedis-3.2.100redis-cli.exe -h 127.0.0.1 -p 6379 -a 123456,其

    2024年02月04日
    浏览(38)
  • Redis启动时提示Creating Server TCP listening socket *:6379: bind: No error

    启动redis-server时需要走配置文件,所以编写了bat脚本启动。 这样就不用每次都输命令了。 但是某次在双击Bat脚本之后,命令框一闪而过。 此时在redis-server.exe所在的目录下打开cmd,输入redis-server.exe redis.windows.conf 会提示: Creating Server TCP listening socket *:6379: bind: No error 注: 博

    2023年04月14日
    浏览(35)
  • socket端口复用之TCP和UDP

    目录 1.什么是端口复用? 2.多个socket可以绑定同一个端口吗? 3.绑定同一端口的多个套接字如何接收数据? 4.SO_REUSEADDR和SO_REUSEPORT选项设置 5.SO_REUSEADDR和SO_REUSEPORT在实际中的运用? 5.1 解决TCP套接字处于TIME_WAIT状态占用端口号问题。 5.2 程序重启后后,端口未释放导致程序重启

    2024年02月07日
    浏览(29)
  • 启动redis出现Creating Server TCP listening socket 127.0.0.1:6379: bind: No error异常

    1.进入redis安装目录,地址栏输入 cmd 2.输入命令 redis启动失败 解决,输入命令 显示以下图标即成功

    2024年02月02日
    浏览(36)
  • TCP通讯(三次握手、四次挥手;滑动窗口;TCP状态转换;端口复用;TCP心跳检测机制)

     前言:建议看着图片,根据文字描述走一遍TCP通讯过程,加深理解。 目录 TCP通信时序: 1)建立连接(三次握手)的过程: 2)数据传输的过程: 3)关闭连接(四次挥手)的过程: 滑动窗口 (TCP流量控制): TCP状态转换: 半关闭: 2MSL: 程序设计中的问题: 端口复用:

    2024年02月03日
    浏览(74)
  • 【网络】TCP通讯(三次握手、四次挥手;滑动窗口;TCP状态转换;端口复用;TCP心跳检测机制)

     前言:建议看着图片,根据文字描述走一遍TCP通讯过程,加深理解。 目录 TCP通信时序: 1)建立连接(三次握手)的过程: 2)数据传输的过程: 3)关闭连接(四次挥手)的过程: 滑动窗口 (TCP流量控制): TCP状态转换: 半关闭: 2MSL: 程序设计中的问题: 端口复用:

    2024年02月07日
    浏览(44)
  • Could not create server TCP listening socket *:6379: bind: 在一个非套接字上尝试了一个操作 。

    Could not create server TCP listening socket *:6379: bind: 在一个非套接字上尝试了一个操作 。 原因: 启动时需要指定配置文件 Could not create server TCP listening socket 127.0.0.1:6379: bind: 操作成功完成。 网上的: redis-cli.exe , shutdown , exit 根本不好使。 网上的:redis根目录新建 Logs 也不好使。

    2024年02月12日
    浏览(30)
  • 4.23 TCP状态转换 4.24半关闭、端口复用

    2MSL(Maximum Segment Lifetime) 主动断开连接的一方,最后进入一个TIME_WAIT状态,这个状态会持续:2msl msl:官方建议:2分钟,实际是30s 当 TCP 连接主动关闭方接收到被动关闭方发送的 FIN 和最终的 ACK 后,连接的主动关闭方必须处于TIME_WAIT 状态并持续 2MSL 时间。 这样就能够让 TCP 连

    2024年02月10日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包