系統分為兩個部分,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...