用Go寫乙個內網穿透工具

2021-10-01 09:22:38 字數 4549 閱讀 5748

系統分為兩個部分,client 和 server,client執行在內網伺服器中,server執行在公網伺服器中,當我們想訪問內網中的服務,我們通過公網伺服器做乙個中繼。

下面是展示我靈魂畫手的時刻了

user傳送請求給 server,server和client建立連線,將請求發給client,client再將請求發給本地程式處理(內網中),然後本地程式將處理結果返回給client,client將結果返回給server,server再將結果返回給使用者,這樣使用者就訪問到了內網中的程式了。

server端監聽兩個埠,乙個用來和user通訊,乙個和client通訊

client啟動時連線server端,並啟動乙個埠監聽本地某程式

當user連線到server埠,將user請求內容發給client

client將從server收到的請求發給本地程式

client將從本地程式收到的內容發給server

server將從client收到的內容發給user即可

當server與client沒有訊息通訊,連線會斷開

client斷開後,再啟動會連線不到server

server端會因為client斷開而引發panic

為了解決這種坑點,加入了心跳包機制,通過5s傳送一次心跳包,保持client與server的連線,同時建立乙個重連通道,監聽該通道,如果當client被斷開後,則往重連通道放乙個值,告訴server端,等待新的client連線,而避免引發panic

更詳細的我就不說了,直接看**,**裡面有詳細的注釋

執行在具有公網ip位址的伺服器端

package main

import

("flag"

"fmt"

"io"

"net"

"runtime"

"strings"

"time"

)var

( localport int

remoteport int

)func

init()

type client struct

// 從client端讀取資料

func

(c *client)

read()

fmt.

println

("讀取出現錯誤..."

) c.exit

}// 收到心跳包,則跳過

if data[0]

=='p'

&& data[1]

=='i'

c.read

:n]}

}// 將資料寫入到client端

func

(c *client)

write()

}}}type user struct

// 從user端讀取資料

func

(u *user)

read()

u.read

:n]}

}// 將資料寫給user端

func

(u *user)

write()

}}}func

main()

}() clientlistener, err := net.

listen

("tcp"

, fmt.

sprintf

(":%d"

, remoteport)

)if err !=

nil fmt.

printf

("監聽:%d埠, 等待client連線... \n"

, remoteport)

// 監聽user來連線

userlistener, err := net.

listen

("tcp"

, fmt.

sprintf

(":%d"

, localport)

)if err !=

nil fmt.

printf

("監聽:%d埠, 等待user連線.... \n"

, localport)

for fmt.

printf

("有client連線: %s \n"

, clientconn.

remoteaddr()

) client :=

&client

userconnchan :=

make

(chan net.conn)

goacceptuserconn

(userlistener, userconnchan)

gohandleclient

(client, userconnchan)

fmt.

println

("重新等待新的client連線..")}

}func

handleclient

(client *client, userconnchan chan net.conn)

go user.

read()

go user.

write()

gohandle

(client, user)}}

}// 將兩個socket通道鏈結

// 1. 將從user收到的資訊發給client

// 2. 將從client收到資訊發給user

func

handle

(client *client, user *user)}}

// 等待user連線

func

acceptuserconn

(userlistener net.listener, connchan chan net.conn)

fmt.

printf

("user connect: %s \n"

, userconn.

remoteaddr()

) connchan

}

執行在需要內網穿透的客戶端中

package main

import

("flag"

"fmt"

"io"

"net"

"runtime"

"strings"

"time"

)var

( host string

localport int

remoteport int

)func

init()

type server struct

// 從server端讀取資料

func

(s *server)

read()

fmt.

println

("從server讀取資料失敗, "

, err.

error()

) s.exit

runtime.

goexit()

}// 如果收到心跳包, 則跳過

if data[0]

=='p'

&& data[1]

=='i'

s.read

:n]}

}// 將資料寫入到server端

func

(s *server)

write()

}}}type local struct

func

(l *local)

read()

l.read

:n]}

}func

(l *local)

write()

}}}func

main()

fmt.

printf

("已連線server: %s \n"

, serverconn.

remoteaddr()

) server :=

&server

go server.

read()

go server.

write()

gohandle

(server)

_= server.conn.

close()

}}func

handle

(server *server)

local :=

&local

go local.

read()

go local.

write()

local.write

for}}

分享乙個內網穿透工具frp

首先簡單介紹一下內網穿透 內網穿透 通過公網,訪問區域網裡的ip位址與埠,這需要將區域網裡的電腦埠對映到公網的埠上 這就需要用到反向 即在公網伺服器上必須執行乙個服務程式,然後在區域網中需要被訪問的電腦上執行乙個客戶端,這樣就可以把本地的埠對映到公網中 編譯好的發行版本 主要檔案介紹 frpc.ex...

用c 寫的乙個詞典工具

使用的qt圖形介面,用libcurl獲取的網頁,在之中遇見了很多問題,一直想用c 類封裝一下libcurl,發現c 很不到家啊。索性用了友元函式。先貼上 吧 main.cpp include stdio.h include stdlib.h include unistd.h include curl...

用c 寫的乙個詞典工具

使用的qt圖形介面,用libcurl獲取的網頁,在之中遇見了很多問題,一直想用c 類封裝一下libcurl,發現c 很不到家啊。索性用了友元函式。先貼上 吧 main.cpp using namespace std include dict.h file fp 定義file型別指標 size t w...