最近做一个 netty 项目,使用 TCP 协议通信,要求是服务端接收到从客户端发出的请求后,将请求的 client IP 和 remote IP 重新修改后转发给远程接口,因为远程接口进行了 client IP 的强校验,另外每个 client IP 对应的远程接口 remote IP 也不一定一样,请问使用 netty 可以达到这种目的吗,或者说有没有什么别的方式可以实现?
1
assiadamo 2023-07-03 15:57:46 +08:00
netty 自带 proxy 的例子看看行不行
https://github.com/netty/netty/tree/4.1/example/src/main/java/io/netty/example/proxy 这种小功能感觉用 java 太重,可以用 golang 试试 |
2
assiadamo 2023-07-03 16:05:14 +08:00
golang 随便抄了一个,就这么简单、
``` package main import ( "flag" "fmt" "io" "log" "net" ) var localAddr *string = flag.String("l", "localhost:9999", "local address") var remoteAddr *string = flag.String("r", "localhost:80", "remote address") func main() { flag.Parse() fmt.Printf("Listening: %v\nProxying: %v\n\n", *localAddr, *remoteAddr) listener, err := net.Listen("tcp", *localAddr) if err != nil { panic(err) } for { conn, err := listener.Accept() log.Println("New connection", conn.RemoteAddr()) if err != nil { log.Println("error accepting connection", err) continue } go func() { defer conn.Close() conn2, err := net.Dial("tcp", *remoteAddr) if err != nil { log.Println("error dialing remote addr", err) return } defer conn2.Close() closer := make(chan struct{}, 2) go copy(closer, conn2, conn) go copy(closer, conn, conn2) <-closer log.Println("Connection complete", conn.RemoteAddr()) }() } } func copy(closer chan struct{}, dst io.Writer, src io.Reader) { _, _ = io.Copy(dst, src) closer <- struct{}{} // connection is closed, send signal to stop proxy } ``` |
3
sdenvi OP @assiadamo 感谢回复,研究一下看看行不行,在做调研时候也是考虑使用 golang , 被否了,公司要求不能使用 Java 之外的语言
|
4
zzzkkk 2023-07-03 16:34:53 +08:00 via Android
|
5
assiadamo 2023-07-03 18:33:00 +08:00
@zzzkkk
在这种情况下,`<-closer` 将会阻塞,直到从 `closer` 通道接收到一个值。 在 `make(chan struct{}, 2)` 中,我们创建了一个带有缓冲大小为 2 的无缓冲通道。这意味着可以向 `closer` 通道发送两个值,而不会立即阻塞。只有当 `closer` 通道的缓冲区已满时,发送操作才会阻塞。 在 `closer <- struct{}{}` 这一行中,我们向 `closer` 通道发送一个值。如果缓冲区仍有空间,该操作会成功并立即返回。如果缓冲区已满,发送操作将会阻塞,直到有空间可用。 在 `<-closer` 这一行中,我们从 `closer` 通道接收一个值。如果通道中有值可用,该操作会成功并立即返回。如果通道为空,接收操作将会阻塞,直到有值可用。 因此,在你提供的代码中,`<-closer` 将会阻塞,直到从 `closer` 通道接收到一个值。这可以用于等待某些操作完成或信号传递。 希望这解答了你的疑问。如果还有进一步的问题,请随时提问。 |
6
oldshensheep 2023-07-03 18:41:14 +08:00
vertx 非常简单,几行代码吧,
public class TcpProxyServer extends AbstractVerticle { private static final int LOCAL_PORT = 8888; private static final String REMOTE_HOST = "1.1.1.1"; private static final int REMOTE_PORT = 80; @Override public void start() { NetServer server = vertx.createNetServer(); server.connectHandler(clientSocket -> { vertx.createNetClient().connect(REMOTE_PORT, REMOTE_HOST, targetSocket -> { if (!targetSocket.succeeded()) { // ? } var remoteSocket = targetSocket.result(); remoteSocket.pipeTo(clientSocket); clientSocket.pipeTo(clientSocket); }); }); server.listen(LOCAL_PORT); } } |
7
oldshensheep 2023-07-03 18:45:41 +08:00
修正一下应该是这样的:
remoteSocket.pipeTo(clientSocket); clientSocket.pipeTo(remoteSocket); 其他的错误处理,连接关闭代码我没写 |
8
zzzkkk 2023-07-03 18:55:31 +08:00 via Android
|
9
sdenvi OP @oldshensheep 没有具体使用过,多问一句,看代码是直接指定了 local IP 和 remote IP ,能够在客户端发送请求的时候从数据流里面拦截到信息之后,通过 ID 从数据库里面读取到 local IP 和 remote IP 重新建立 TCP 请求发送到后端服务器吗?
|
10
sdenvi OP @oldshensheep 类似 netty ,道连接成功触发 channelActive ,数据传输时触发 channelRead
|
11
oldshensheep 2023-07-03 22:12:33 +08:00
可以的,在客户端建立连接后,客户端发个 ID ,然后服务端读取 ID 查数据库得到 remote IP ,再建立连接也行。
大概这样吧 public void start() { NetServer server = vertx.createNetServer(); server.connectHandler(clientSocket -> { String[] remote = { "" }; clientSocket.handler(b -> { var id = b.getBytes(0, 1); // 查数据库的到 remote IP remote[0] = "1.1.1.1"; }); vertx.createNetClient().connect(REMOTE_PORT, remote[0], targetSocket -> { if (!targetSocket.succeeded()) { // ? } var remoteSocket = targetSocket.result(); remoteSocket.pipeTo(clientSocket); clientSocket.pipeTo(remoteSocket); }); }); server.listen(LOCAL_PORT); } |
12
sdenvi OP @oldshensheep 想最终达到的目的就是类似 nat 的功能:客户端 ---> server <---> client ---> remote app 这样的效果,客户端和 TCP 的 server 端建立连接后读取数据流,从数据流里面获取到用户 ID ,拿到 ID 后发送给 TCP 的 client 端,client 端根据 ID 查询到保存到数据库的 client IP 和 remote IP 后重新进行 socket bind ,达到让 remote app 通过 IP 校验。如果只是 proxy 的话直接做转发就行,不用额外的处理,涉及到重新绑定四元组,一时想不到好的解决方案了
|