V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
voidmnwzp
V2EX  ›  Go 编程语言

如何在同一个端口上建立不同的连接?

  •  
  •   voidmnwzp ·
    NullpointerW · 2023-07-19 19:35:14 +08:00 · 2600 次点击
    这是一个创建于 500 天前的主题,其中的信息可能已经有所发展或是发生改变。

    根据四元组,一个连接对应一个连接型 socket 应该是可行的 连接 a local:12301->local:689 连接 b local:12301->local:8080

    20 条回复    2023-07-25 10:56:29 +08:00
    ManjusakaL
        1
    ManjusakaL  
       2023-07-19 19:38:15 +08:00
    On TCP 的链接是你应用的概念。你直接自定义一套报文结构不就行了
    flyqie
        2
    flyqie  
       2023-07-19 19:39:24 +08:00
    你想用来干啥。。

    想不通。
    xuanbg
        3
    xuanbg  
       2023-07-19 19:41:07 +08:00
    没明白 OP 的问题是什么?服务端监听 80 端口,有两个客户端,分别是 123->80 | 124->80 ,这完全没有问题啊
    voidmnwzp
        4
    voidmnwzp  
    OP
       2023-07-19 20:01:08 +08:00
    网页端的正文按 ctrl+enter 居然是直接发送无法换行 什么 nt 设定。。。。
    ``` go

    host0 := "remote"
    port0 := "8080"

    host1 := "remote"
    port1 := "689"

    // 本机端口
    localPort := "12301"

    // 创建本机地址
    localAddr, err := net.ResolveTCPAddr("tcp", "localhost:"+localPort)
    if err != nil {
    fmt.Println("Error resolving local address:", err)
    os.Exit(1)
    }

    // 创建远程地址 8080
    remoteAddr0, err := net.ResolveTCPAddr("tcp", host0+":"+port0)
    if err != nil {
    fmt.Println("Error resolving remote address:", err)
    os.Exit(1)
    }
    // 创建远程地址 689
    remoteAddr1, err := net.ResolveTCPAddr("tcp", host1+":"+port1)
    if err != nil {
    fmt.Println("Error resolving remote address:", err)
    os.Exit(1)
    }
    // 建立连接
    go dial(localAddr, remoteAddr0)
    dial(localAddr, remoteAddr1)
    ```
    ``` go
    func dial(l, r *net.TCPAddr) {
    localConn, err := net.DialTCP("tcp", l, r)
    if err != nil {
    fmt.Println("Error connecting to remote host:", err)
    os.Exit(1)
    }
    localConn.Write([]byte("ping"))
    }
    ```
    bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.

    我想用本机上的同一个端口去连接不同的服务器,但这个好像在 netty 上可以实现,不知道在 go 上如何实现,go 在 dialTcp 的时候,将 socket bind 了端口
    voidmnwzp
        5
    voidmnwzp  
    OP
       2023-07-19 20:01:44 +08:00
    ysc3839
        6
    ysc3839  
       2023-07-19 20:10:27 +08:00 via Android
    natmap https://github.com/heiher/natmap 似乎就能实现类似效果
    可以问一下作者 @heiher 相关细节
    leonshaw
        7
    leonshaw  
       2023-07-19 20:15:02 +08:00 via Android
    Control 里把 SO_REUSEPORT 设置上
    gps949
        8
    gps949  
       2023-07-19 20:24:02 +08:00
    heiher
        9
    heiher  
       2023-07-19 22:13:07 +08:00
    在 Linux 上可以直接创建多个 TCP socket 绑定同一个端口来连接至多个不同的目的地址:端口,也不需要开启 reuseport 。但如果该端口已经被某个 socket 绑定并且处于 listen 状态则不行。
    zachary99
        10
    zachary99  
       2023-07-19 22:35:15 +08:00 via Android
    自定义一个报头,标记两种不同流量
    mikewang
        11
    mikewang  
       2023-07-19 22:42:23 +08:00
    我看是在 Go 板块的贴,对于 Go 说那就是 go-reuseport 。

    一些操作系统比如 Windows ,两个 socket 中一个绑定「 0.0.0.0:12301 」另一个绑定「本机 IP:12301 」,不需要其他的操作就能满足你的要求。
    rrfeng
        12
    rrfeng  
       2023-07-19 22:54:00 +08:00 via Android
    突然发现之前啃了好久的 bind 和 connect 在处理这个本地端口上的逻辑全忘光了……
    qbqbqbqb
        13
    qbqbqbqb  
       2023-07-20 01:29:35 +08:00
    bind 之前开启 SO_REUSEADDR 选项(注意不是 SO_REUSEPORT )
    qbqbqbqb
        14
    qbqbqbqb  
       2023-07-20 01:36:26 +08:00
    这个是 Linux 的特性,Linux 在 bind 本地端口时默认采用三元组(协议、源地址、源端口)判断冲突,有冲突即不能 bind (错误信息为 address already in use ,注意这个错误信息,暗示了后面应该开启什么选项)。

    同时,在 socket 上提供了一个 SO_REUSEADDR 的选项,开启之后可以绕过这个 bind 时期的三元组检查。(由于 TCP/IP 协议本身的特性,仍然需要保证五元组不能冲突,否则后续的 connect 或 listen 操作仍然会出错)

    注意 SO_REUSEPORT 选项是另外一个用途,和这个问题无关。
    cnbatch
        15
    cnbatch  
       2023-07-20 02:29:32 +08:00
    ctrl+enter = 发送
    这是早期聊天软件(包括 QQ )的习惯,接触互联网足够早的话,会对这个快捷键很熟悉

    V 站网页版编辑框换行的话,直接按 Enter 就行了,不需要加什么 CTRL SHIFT 之类的
    lysS
        16
    lysS  
       2023-07-20 09:12:52 +08:00
    @leonshaw reuse 只能多个进程 read 同一个 socket ,bind 也只能绑定一个地址,不然就违反了五元组的限制。可以用 UDP 或 IPConn 的 WriteTo 实现对多通信
    daokedao
        17
    daokedao  
       2023-07-20 09:14:37 +08:00
    UDP 就可以啊
    Goooooos
        18
    Goooooos  
       2023-07-20 09:21:21 +08:00
    你是想实现流量中转?
    leonshaw
        19
    leonshaw  
       2023-07-20 10:17:44 +08:00
    @lysS 这个讲的比较清楚: https://stackoverflow.com/a/14388707
    wkong
        20
    wkong  
       2023-07-25 10:56:29 +08:00
    设置 SO_REUSEPORT 就可以了,参考我开源的单机百万实时通讯服务(自研消息 DB ,二进制协议,重写 go 底层 epoll 网络)
    https://github.com/WuKongIM/WuKongIM
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2580 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 03:48 · PVG 11:48 · LAX 19:48 · JFK 22:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.