Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
編最近對Node特別感興趣,所以就趁著周末的時間搭了一個簡單的登錄注冊的一個小后臺。
這部分主要是,從前端發送ajax請求到后臺,如果返回參數是成功,則登錄,否則,打印相關參數;
代碼
這是界面
后臺用的是Node.js,框架用的express,數據庫用的mysql;
數據庫結構
表結構
node代碼如下:
express是node的基礎框架,這里邊有坑的地方是:返回值的時候,必須返回對象。
掌握一門后臺語言,對于現在的前端工作來說,越來越重要了,代碼之路,漫漫求索,共勉之,兄弟姐妹們。
于網絡用戶來說,一定都經歷過出門在外無法直接在異地訪問公司的ERP系統、或是難以部署異地遠程桌面,因此心急如焚的情況;對于企業來說,無論是財務管理軟件難以將分店信息同步到總部進行統計匯總、還是員工出差在外或在家里就不能訪問企業內部辦公系統,都極大地影響了公司整體效率;對于個人開發者來說,微信小程序或者在線支付系統等開發環境往往需要一個可以環境進行調試,不然的話,難以進行開發調試。
諸如此類的難題眾多,但解決方法其實很簡單,那就是使用軟件或者自己手寫一個,可以支持訪問我的電腦上的微信支付接口,從而實現這一系列的簡易操作。目前國內這方面企業級的服務商有**殼和神卓互聯,我接觸過很多公司在用,**殼的技術是PHTunnel ,神卓互聯用的是Wangooe Tunnel技術,這里就介紹神卓互聯的,接下來就介紹和分析這款軟件的用法和技術要點。如果沒有接觸過這方面技術的同學可以看一下這個圖:
首先用法很簡單,就是在界面上創建一條映射規則,填寫應用名稱和要連接的內網應用主機地址和端口號,
填寫自己要穿透的應用名稱和端口號,如果需要獲取原訪問者IP最好是選擇Web應用。提交提交就可以了。
例如我需要發布一個Tomcat應用,訪問端口號是7070,那么應用名稱填寫tomcat,內網主機填寫127.0.0.1,內網端口填7070點提交就可以。
首先新建一個web項目
新建login.jsp登陸文件,內容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登錄系統</title>
<style type="text/css">
table td{font: 14px/1.5 'Microsoft YaHei',arial,tahoma,\5b8b\4f53,sans-serif;}
</style>
</head>
<body>
<table>
<tr><td>用戶名</td><td><input type="text"></td></tr>
<tr><td>密碼</td><td><input type="text"></td></tr>
<tr><td> </td><td><input type="submit" value="登錄"></td></tr>
</table>
</body>
</html>
先在本地運行,看項目是否可以正常運行:
本地運行沒有問題,可以正常打開,接下來就試一下外網訪問
打開神卓互聯軟件主界面,右鍵選擇外網訪問
如果需要綁定域名訪問的話也很簡單,這里不多說。
接下來就分析是如何做到將請求轉發到內網因為又返回給訪問客戶端的。
InetAddress
//獲取本機的InetAddress實例
InetAddress address=InetAddress.getLocalHost();
address.getHostName();//獲取計算機名
address.getHostAddress();//獲取IP地址
byte[] bytes=address.getAddress();//獲取字節數組形式的IP地址,以點分隔的四部分
//獲取其他主機的InetAddress實例
InetAddress address2=InetAddress.getByName("其他主機名");
InetAddress address3=InetAddress.getByName("IP地址");
URL類
//創建一個URL的實例
URL baidu=new URL("http://www.baidu.com");
URL url=new URL(baidu,"/index.html?username=tom#test");//?表示參數,#表示錨點
url.getProtocol();//獲取協議
url.getHost();//獲取主機
url.getPort();//如果沒有指定端口號,根據協議不同使用默認端口。此時getPort()方法的返回值為 -1
url.getPath();//獲取文件路徑
url.getFile();//文件名,包括文件路徑+參數
url.getRef();//相對路徑,就是錨點,即#號后面的內容
url.getQuery();//查詢字符串,即參數
以下就是P2P打洞核心代碼(TCP)
假設現在有以下3臺機器:
外網機器,IP:121.56.21.85 , 以下簡稱“主機A”
處在內網1下的機器,外網IP:106.116.5.45 ,內網IP:192.168.1.10, 以下簡稱“主機1”
處在內網2下的機器,外網IP:104.128.52.6 ,內網IP:192.168.0.11,以下簡稱“主機2”
很顯然內網的兩臺機器不能直接連接,我們現在要實現的是借助外網機器,讓兩臺內網機器進行tcp直連通訊。
實現過程如下:
1、主機A啟動服務端程序,監聽端口8888,接受TCP請求。
2、啟動主機1的客戶端程序,連接主機A的8888端口,建立TCP連接。
3、啟動主機2的客戶端程序,連接主機A的8888端口,建立TCP連接。
4、主機2發送一個命令告訴主機A,我要求與其他設備進行連接,請求協助進行穿透。
5、主機A接收到主機2的命令之后,會返回主機1的外網地址和端口給主機2,同時把主機2的外網地址和端口發送給主機1。
6、主機1和主機2在收到主機A的信息之后,同時異步發起對對方的連接。
7、在與對方發起連接之后,監聽本地與主機A連接的端口(也可以在發起連接之前),(由于不同的操作系統對tcp的實現不盡相同,有的操作系統會在連接發送之后,把對方的連接當作是回應,即發出SYN之后,把對方發來的SYN當作是本次SYN的ACK,這種情況就不需要監聽也可建立連接,本文的代碼所在測試環境就不需要監聽,測試環境為:服務器centos 7.3, 內網1 win10,內網2 win10和centos7.2都測試過)。
8、主機1和主機2成功連上,可以關閉主機A的服務,主機1和主機2的連接依然會持續生效,不關閉就形成了一個3方直連的拓撲網狀結構網絡。
服務器端代碼:
package org.inchain.p2p;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 外網端服務,穿透中繼
*
* @author ln
*
*/
public class Server {
public static List<ServerThread> connections=new ArrayList<ServerThread>();
public static void main(String[] args) {
try {
// 1.創建一個服務器端Socket,即ServerSocket,指定綁定的端口,并監聽此端口
ServerSocket serverSocket=new ServerSocket(8888);
Socket socket=null;
// 記錄客戶端的數量
int count=0;
System.out.println("***服務器即將啟動,等待客戶端的連接***");
// 循環監聽等待客戶端的連接
while (true) {
// 調用accept()方法開始監聽,等待客戶端的連接
socket=serverSocket.accept();
// 創建一個新的線程
ServerThread serverThread=new ServerThread(socket);
// 啟動線程
serverThread.start();
connections.add(serverThread);
count++;// 統計客戶端的數量
System.out.println("客戶端的數量:" + count);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package org.inchain.p2p;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
/**
* 外網端服務多線程處理內網端連接
*
* @author ln
*
*/
public class ServerThread extends Thread {
// 和本線程相關的Socket
private Socket socket=null;
private BufferedReader br=null;
private PrintWriter pw=null;
public ServerThread(Socket socket) throws IOException {
this.socket=socket;
this.br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.pw=new PrintWriter(socket.getOutputStream());
}
// 線程執行的操作,響應客戶端的請求
public void run() {
InetAddress address=socket.getInetAddress();
System.out.println("新連接,客戶端的IP:" + address.getHostAddress() + " ,端口:" + socket.getPort());
try {
pw.write("已有客戶端列表:" + Server.connections + "\n");
// 獲取輸入流,并讀取客戶端信息
String info=null;
while ((info=br.readLine()) !=null) {
// 循環讀取客戶端的信息
System.out.println("我是服務器,客戶端說:" + info);
if (info.startsWith("newConn_")) {
//接收到穿透消息,通知目標節點
String[] infos=info.split("_");
//目標節點的外網ip地址
String ip=infos[1];
//目標節點的外網端口
String port=infos[2];
System.out.println("打洞到 " + ip + ":" + port);
for (ServerThread server : Server.connections) {
if (server.socket.getInetAddress().getHostAddress().equals(ip)
&& server.socket.getPort()==Integer.parseInt(port)) {
//發送命令通知目標節點進行穿透連接
server.pw.write("autoConn_" + socket.getInetAddress().getHostAddress() + "_" + socket.getPort()
+ "\n");
server.pw.flush();
break;
}
}
} else {
// 獲取輸出流,響應客戶端的請求
pw.write("歡迎您!" + info + "\n");
// 調用flush()方法將緩沖輸出
pw.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("客戶端關閉:" + address.getHostAddress() + " ,端口:" + socket.getPort());
Server.connections.remove(this);
// 關閉資源
try {
if (pw !=null) {
pw.close();
}
if (br !=null) {
br.close();
}
if (socket !=null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public String toString() {
return "ServerThread [socket=" + socket + "]";
}
}
最后附上測試方法和運行效果:
使用方法:
1、在服務器啟動Server。
2、在客戶端1啟動Client,輸入notwait命令,等待服務器通知打洞。
3、在客戶端2啟動Client,輸入conn命令,然后輸入服務器返回的客戶端1的外網ip和端口,接下來就會自動完成連接。
運行效果:
客戶端1運行結果 (穿透成功之后,客戶端會把穿透對方返回的內容發送給服務器,服務器再返回)
客戶端1使用netstat查看的網絡連接
客戶端2的運行結果
客戶端2使用netstat查看的網絡連接
可以看到客戶端2對應的端口不同,那是因為電信NAT的問題,本地獲取的Ip是電信10開頭的內網地址,相當于在客戶端2的上層還進行了一次中繼。
s:由于沒有對稱型的NAT設備,無法做深入研究,對稱型設備的端口太難猜測,穿透成功概率很小。
team登錄不上/網頁打不開無法加載怎么辦 最新解決方法分享
Steam國服和國際服啊,它們還是有區別的。國服Steam有個新名字,叫蒸汽平臺,因為服務器就在咱們國內,所以網頁打開速度飛快,基本不會出錯。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。