• Linux C++ 网络编程学习系列(1)——端口复用实现


    Linux C++ 网络编程学习系列(1)——端口复用实现

    1. 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse
    2. 源码说明:
      • server1.cpp: 监听127.1:6666,功能是将收到的小写转大写
      • server2.cpp: 监听192.132:6666, 功能是接收数据, 将自己的数据从大写转小写, 把不是自己的数据转发给server1处理(判断方法是头三个字符是不是123)
      • client.cpp: 客户端, 地址在: https://github.com/whuwzp/linuxc/tree/master/simple_cs/client/

    1. 概要

    起因: 由socket状态转换图可知, 主动关闭连接的一端都会有一个TIME_WAIT, 时间为2msl, 以确保对端收到最后一个ACK
    影响: 如果是服务器端需要主动断开连接(例如网站更新等), 那么再次重启则需要浪费2msl时间, 为了减少这种时间开销, 因此有了端口复用
    作用: 可以立马重启服务器, 而不必等待2msl, 且不会在bind的时候发生端口被占用的错误.

    2. 核心代码

    2.1 server1

    //server1.cpp
    
    
    #define LOCALIP "127.0.0.1"
    #define PORT 6666
    
    // 127.1:6666. startsock里面很简单,就是socket函数
    startsock(fd_server, sock_server, LOCALIP, PORT);
    opt = 1;
    //设置为端口复用
    Setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &opt, (socklen_t)sizeof(opt));
    
    

    2.2 server2

    //server2.cpp
    
    
    #define LOCALIP "127.0.0.1"
    #define PUBLICIP "192.168.153.132"
    #define myflag "123"
    #define PORT 6666
    
    //这是连接server1, 也就是127.1:6666
    startsock(fd_local, sock_local, LOCALIP, PORT);
    opt = 1;
    Setsockopt(fd_local, SOL_SOCKET, SO_REUSEADDR, &opt, (socklen_t)sizeof(opt));
    
    //这是绑定192.132:6666的公网地址
    startsock(fd_server, sock_server, PUBLICIP, PORT);
    opt = 1;
    Setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &opt, (socklen_t)sizeof(opt));
    
    while (true) {
            ret = (int)Read(fd_client, recvbuf, sizeof(recvbuf));
            if (ret == 0) {
                break;
            }
            strcpy(cmpstr, recvbuf);
            cmpstr[strlen(myflag)] = '';
            /*看看是不是我的数据包,如果不是,则交给127.1:6666端口处理*/
            if (strcmp(cmpstr, myflag) != 0) {
                printf("going to send to local
    ");
                Write(fd_local, recvbuf, strlen(recvbuf) + 1);//发给server1处理
                Read(fd_local, sendbuf, sizeof(sendbuf)); //接收server1的返回结果
                Write(fd_client, sendbuf, strlen(sendbuf) + 1);//把返回结果转给客户
                continue;
            }
    
            //是我的,我来处理
            printf("recv from %s:%d :  string: %s
    ",
                   inet_ntoa(clientinfo->addr.sin_addr),
                   ntohs(clientinfo->addr.sin_port), recvbuf);
    
            handler(recvbuf + strlen(myflag), sendbuf);//函数功能: 将大写转为小写
            ret = (int)Write(fd_client, sendbuf, strlen(sendbuf) + 1);
            if (ret == 0) {
                break;
            }
        }
    

    2.3 运行结果

    # client
    input:hello # 输入hello
    send : 6 nbytes
    recv: 6 bytes, string: HELLO # 由server1处理了
    input:123HEllo # 输入123HEllo
    send : 9 nbytes
    recv: 6 bytes, string: hello # 由server2处理了
    
    # server1
    accept: 127.0.0.1: 55526
    recv from 127.0.0.1:55526 :  string: hello
    
    # server2
    accept: 192.168.153.132: 55558
    going to send to local
    recv from 192.168.153.132:55558 :  string: 123HEllo
    

    3. 参考网址

    参考视频:https://www.bilibili.com/video/av53016117?p=48
    参考网址:https://www.cnblogs.com/royi123/archive/2013/03/12/2956655.html

  • 相关阅读:
    ubuntu12.04.2上利用cmake安装opencv2.4.6
    微软无线鼠标3500滚轮问题
    Linux 安装 Tomcat
    Linux 安装 MySQL
    Linux 安装 JDK
    Linux 安装 Redis 及踩坑
    IDEA Git 撤销push(回退到指定版本)
    【Java】Ajax实现级联城市
    node.js更换镜像源
    【Java】数据库连接池的简单使用
  • 原文地址:https://www.cnblogs.com/whuwzp/p/linux_cpp_network_1.html
Copyright © 2020-2023  润新知