Linux 关闭睿频
关闭睿频
sudo sh -c "echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo"
设置CPU最大频率到60%
sudo sh -c "echo 60 > /sys/devices/system/cpu/intel_pstate/max_perf_pct"
sudo sh -c "echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo"
sudo sh -c "echo 60 > /sys/devices/system/cpu/intel_pstate/max_perf_pct"
假设本机局域网地址:lh_ip,远程公共网服务器地址:rh_ip。
将本地的某个端口lport映射到远程主机的某个端口rport上
ssh remote_user@rh_ip -L lport:remote_host:rport
remote_host==127.0.0.1则表示远程主机rh_ip.
这样就可以通过访问本机lh_ip的lport, 来访问远程主机remote_host的rport端口.
将远程主机的某个端口rport映射到本地的某个端口lpor上
ssh user@rh_ip -R rport:local_host:lport
这样就可以通过访问rh_ip的rport端口, 来访问local_host的lport端口.
默认情况下rport仅bind到127.0.0.1上,如果需要端口bind到所有地址,
则需要在/etc/ssh/sshd_config中,添加:
GatewayPorts yes
保持连接
ssh user@rh_ip -o "ServerAliveInterval 30"
每30秒向服务器发送一次响应请求.
-N 不使用Shell交互, 仅用转发可用这个参数
ssh -N user@rh_ip
自动接受SSH密钥指纹
ssh user@rh_ip -o "StrictHostKeyChecking=no"
在使用Gtk开发应用程序的过程中,如果需要内嵌网页,那么使用libwebkit2gtk是个非常自然和正确的选择。那么这里就可能原生程序代码可能需要跟网页交互的问题。
Gtk程序跟网页的交互,主要有两个方面:
1 Gtk程序需要调用网页js代码
2 网页需要调用Gtk程序的功能代码
需求1,使用webkit2gtk的内置webkit_web_view_run_javascript
函数即可解决
需求2,使用webkit2gtk的内置的web extendsion扩展支持功能解决 或 window.webkit.messageHandlers.
不多说看代码吧!
webviewgtk.c
/**
*
* Copyright (C) 2020 Wei Keting<weikting@gmail.com>. All rights reserved.
* @Time : 2021-04-04 12:18
* @Last Modified: 2022-12-10 17:27
* @File : webviewgtk.c
* @Description :
*
* 依赖下载:
* sudo apt install libwebkit2gtk-4.0-doc libwebkit2gtk-4.0-dev libgtk-3-dev
* gcc webviewgtk.c -o webviewgtk -D_GNU_SOURCE -g3 -Wall `pkg-config --cflags --libs webkit2gtk-4.0`
*
*/
#include <gtk/gtk.h>
#include <glib.h>
#include <webkit2/webkit2.h>
#include <sys/types.h>
#include <unistd.h>
static void
web_view_javascript_finished (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
WebKitJavascriptResult *js_result;
JSCValue *value;
GError *error = NULL;
js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
if (!js_result) {
g_warning ("Error running javascript: %s", error->message);
g_error_free (error);
return;
}
value = webkit_javascript_result_get_js_value (js_result);
if (jsc_value_is_string (value)) {
JSCException *exception;
gchar *str_value;
str_value = jsc_value_to_string (value);
exception = jsc_context_get_exception (jsc_value_get_context (value));
if (exception)
g_warning ("Error running javascript: %s", jsc_exception_get_message (exception));
else
g_print ("Script result: %s\n", str_value);
g_free (str_value);
} else {
g_warning ("Error running javascript: unexpected return value");
}
webkit_javascript_result_unref (js_result);
}
static gboolean
on_webview_load_failed(WebKitWebView *webview,
WebKitLoadEvent load_event,
gchar *failing_uri,
GError *error,
gpointer user_data)
{
g_printerr("%s: %s\n",failing_uri,error->message);
return FALSE;
}
static void
handle_script_message (
WebKitUserContentManager* self,
WebKitJavascriptResult* js_result,
gpointer user_data)
{
JSCValue *value;
value = webkit_javascript_result_get_js_value (js_result);
JSCException *exception;
gchar *str_value;
str_value = jsc_value_to_string (value);
exception = jsc_context_get_exception (jsc_value_get_context (value));
if (exception)
g_warning ("Error running javascript: %s", jsc_exception_get_message (exception));
else
g_printerr ("Script result: %s\n", str_value);
g_printerr("%s: %s\n",__func__,str_value);
g_free (str_value);
}
static void
on_button_clicked(GtkButton *button,
WebKitWebView *webview)
{
static gint t = 0;
gchar buf[128]={0};
g_snprintf(buf,sizeof(buf)-1,"change_span_id('_n%d')",t);
t+=1;
//在webview当前的html页面中直接运行js代码
webkit_web_view_run_javascript(webview,buf,NULL,web_view_javascript_finished,NULL);
}
static void
webkit_web_extension_initialize (WebKitWebContext *context,
gpointer user_data)
{
g_printerr("%s: %d\n",__FUNCTION__,getpid());
//设置web extendsion扩张.so文件的搜索目录
webkit_web_context_set_web_extensions_directory(context,".");
}
/**
** 创建window,添加webkit控件
**
**/
static void
on_activate (GtkApplication *app)
{
GtkWindow *window;
g_assert (GTK_IS_APPLICATION (app));
window = gtk_application_get_active_window (app);
if (window == NULL)
window = g_object_new (GTK_TYPE_WINDOW,
"application", app,
"default-width", 600,
"default-height", 300,
NULL);
//注册处理web extensions的初始化函数
g_signal_connect(webkit_web_context_get_default(),"initialize-web-extensions",G_CALLBACK(webkit_web_extension_initialize),NULL);
GtkWidget* webview = webkit_web_view_new();
g_signal_connect (webview, "load-failed", G_CALLBACK (on_webview_load_failed), NULL);
// 加载网页
GFile *file = g_file_new_for_path("webview.html");
gchar *uri = g_file_get_uri(file);
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), uri);
g_free(uri);
g_object_unref(file);
// 注册 window.webkit.messageHandlers.msgToNative.postMessage(value)
// 的回调函数
WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW(webview));
g_signal_connect (manager, "script-message-received::msgToNative",
G_CALLBACK (handle_script_message), NULL);
webkit_user_content_manager_register_script_message_handler (manager, "msgToNative");
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
GtkWidget *button = gtk_button_new_with_label ("change span");
gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(webview),TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(button),FALSE,TRUE,0);
gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(vbox));
gtk_widget_show_all(GTK_WIDGET(vbox));
gtk_window_present (window);
g_signal_connect (button, "clicked", G_CALLBACK (on_button_clicked), webview);
}
int
main (int argc,
char *argv[])
{
g_autoptr(GtkApplication) app = NULL;
int ret;
app = gtk_application_new ("com.weiketing.webkit_webview", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
ret = g_application_run (G_APPLICATION (app), argc, argv);
return ret;
}
web_exten.c
/**
*
* Copyright (C) 2020 Wei Keting<weikting@gmail.com>. All rights reserved.
* @Time : 2021-04-04 12:18
* @File : web_exten.c
* @Description :
*
* 依赖下载:
* sudo apt install libwebkit2gtk-4.0-doc libwebkit2gtk-4.0-dev libgtk-3-dev
* gcc web_exten.c -o libweb_exten.so -shared -Wl,-soname,libweb_exten.so -D_GNU_SOURCE -g3 -Wall `pkg-config --cflags --libs webkit2gtk-4.0`
**/
#include <glib.h>
#include <webkit2/webkit-web-extension.h>
#include <sys/types.h>
#include <unistd.h>
static gint
js_app_add(gpointer *first,gint num)
{
static gint N = 0;
g_printerr("%s: %p\n",__FUNCTION__,first);
N += num;
return N;
}
static void
window_object_cleared_callback (WebKitScriptWorld *world,
WebKitWebPage *web_page,
WebKitFrame *frame,
gpointer user_data)
{
JSCContext* jsContext;
jsContext = webkit_frame_get_js_context_for_script_world (frame, world);
//添加一个js全局变量gtkValue
jsc_context_set_value(jsContext,"gtkValue",jsc_value_new_string(jsContext,"__test_js_exten"));
/* Use JSC API to add the JavaScript code you want */
//注册一个名为NativeTest的js类
JSCClass* app = jsc_context_register_class(jsContext,"NativeTest",NULL,NULL,NULL); // g_object_new(JSC_TYPE_CLASS,"name","JSApp","context",jsContext,NULL);
//给JSCClass类添加add方法
jsc_class_add_method(app,"add",G_CALLBACK(js_app_add),NULL,NULL,G_TYPE_INT,1,G_TYPE_INT,NULL);
//创建一个obj,作为JSCClass类绑定实例,JSCClass方法回调的第一个参数就是obj
GObject *obj = g_object_new(G_TYPE_OBJECT,NULL);
jsc_context_set_value(jsContext,"GtkNative",jsc_value_new_object(jsContext,obj,app));
g_printerr("%s: %d %p\n",__FUNCTION__,getpid(),obj);
g_object_unref(obj);
}
G_MODULE_EXPORT void
webkit_web_extension_initialize (WebKitWebExtension *extension)
{
//web extension的初始化函数
g_signal_connect (webkit_script_world_get_default (),
"window-object-cleared",
G_CALLBACK (window_object_cleared_callback),
NULL);
}
内嵌的网页示例,webview.html
<!DOCTYPE html>
<html lang="zh">
<!--filename: webview.html -->
<head>
<meta charset="utf-8"/>
<meta http-equiv="Content-Language" content="zh-CN">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="referrer" content="always"/>
<title>Webkit Webview test</title>
<script type="text/javascript">
function change_span_id(v=''){
//alert("test")
document.getElementById('span_id').innerHTML = 'test'+v+gtkValue
return v
}
function native_add(num){
//调用自定义添加的js接口
i= GtkNative.add(num)
document.getElementById('add').innerHTML = i
}
function send2Gtk(){
e = document.getElementById('msg')
window.webkit.messageHandlers.msgToNative.postMessage(e.value)
}
</script>
</head>
<body>
<span>words for test: </span><span id="span_id"></span>
<br/>
<button onclick="change_span_id()">change span id</button>
<br/>
<span>Native add: </span><span id='add'></span>
<br/>
<button onclick="native_add(2)">Native Add</button>
<br/>
<input type="text" id="msg" />
<br/>
<button onclick="send2Gtk()">Send to Native</button>
</body>
</html>
Web Extension相比于window.webkit.messageHandlers.
的优点是有返回值。
安装依赖:
sudo apt install libwebkit2gtk-4.0-doc libwebkit2gtk-4.0-dev libgtk-3-dev
把webviewgtk.c,web_exten.c, webview.html放在同一目录下。
编译程序:
gcc web_exten.c -o libweb_exten.so -shared -Wl,-soname,libweb_exten.so -D_GNU_SOURCE -g3 -Wall `pkg-config --cflags --libs webkit2gtk-4.0`
gcc webviewgtk.c -o webviewgtk -D_GNU_SOURCE -g3 -Wall `pkg-config --cflags --libs webkit2gtk-4.0`
运行程序:
./webviewgtk
Ubuntu 22.10默认使用PipeWire作为声音服务器,替换之前的PulseAudio。
PipeWire是个新东西,算是刚刚开始较大范围使用,结果就是表现的不太行。
至少在我自己的ThinkPad X1上就没有声音。解决的办法也很简单就用PulseAudio。
具体操作:
sudo apt install --yes pulseaudio pulseaudio-module-bluetooth pulseaudio-utils gstreamer1.0-pulseaudio
因为很多桌面系统组件都有依赖PipeWire,卸载PipeWire是个问题,所以就不卸载了。
想办法不让TA起来就可以啦。
具体操作:
systemctl --user disable pipewire{,-pulse}.service
systemctl --user stop pipewire{,-pulse}.{socket,service}
tmpdr=/usr/lib/systemd/user/backups
sudo mkdir -p ${tmpdr}
sudo mv /usr/lib/systemd/user/pipewire* ${tmpdr}
systemctl --user enable pulseaudio.service
systemctl --user start pulseaudio
经过上述操作,Ubuntu 22.10就能正常出声音了
虽然PipeWire相比PulseAudio是新技术,但还没有经过大量机器和时间的考验,
预计还得经过很长时间才能做到安装完成后立即可用。
我们都知道自签名https证书默认是不被系统信任的。
所以访问使用自签名证书的网站,默认一般都是终止访问,提示错误。
面对自签名证书导致的错误提示,我们可以:
1、无视继续;
2、用户手动导入自签名证书CA(Certificate Authority)进系统并信任证书;
3、应用自带自签名证书;
本文主要说一下Android App自带自签名证书CA一些做法。
这里常规App是指使用Android SDK开发,或者基于Android SDK API的框架开发的App。
在Manifest.xml的application添加android:networkSecurityConfig,如:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
...
>
...
</application>
</manifest>
添加文件res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/extra_cas"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
自签证书的CA,就写进文件res/raw/extra_cas(可以放多个):
-----BEGIN CERTIFICATE-----
Content Of CA1 .....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Content Of CA2 .....
-----END CERTIFICATE-----
.....
目前网络安全配置文件,仅适用Android 7.0+。
测试有效的API:WebView,URLConnection,okhttp
无效的API:Flutter HttpClient
网络安全配置文件对Flutter开发的App是无效的。需要另想办法。
在项目源码目录下,创建assets目录,然后CA保存到文件asset/extra_cas。
然后添加代码如下:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static Object ca = "";
@override
Widget build(BuildContext context) {
if (ca == "")ca = setupRootCA();
......
}
static Object setupRootCA (){
var ft = rootBundle.load('assets/extra_cas');
ft.then((ByteData value) {
SecurityContext.defaultContext.setTrustedCertificatesBytes(value.buffer.asUint8List());
return null;
});
return Object();
}
......
}
原先使用HttpClient的代码,无需任何修改就可以支持使用自签名证书的https链接了。
原生代码和flutter混合的项目,如果不介意在apk放两个相同CAs文件,
其实很简单的(flutter和原生用不同文件)。
那么如果我们想项目就放一份CAs文件呢?假设就用res/raw/extra_cas这个文件,还是有办法的。
具体做方法:
网络安全配置还是照样搞
在Flutter入口Activity,添加代码:
public class MainActivity extends FlutterActivity {
......
//读取CAs文件的内容
protected byte[] getTrustedCA(){
InputStream in = getResources().openRawResource(R.raw.extra_cas);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int n = 0;
while (true){
try {
if ((n = in.read(buf))<=0) break;
bao.write(buf,0,n);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return bao.toByteArray();
}
//对接Flutter的调用
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "flutter.app.share")
.setMethodCallHandler(
(call, result) -> {
if (call.method.contentEquals("getTrustedCA")) {
result.success(getTrustedCA());
}
}
);
}
......
}
修改之前的方法setupRootCA:
static Object setupRootCA ()
{
Future ft = const MethodChannel('flutter.app.share').invokeMethod('getTrustedCA');
ft.then((value) {
Uint8List ca = value;
SecurityContext.defaultContext.setTrustedCertificatesBytes(ca);
return null;
});
return Object();
}
https的证书一般都给出自己有效的域名和IP。创建证书时一般域名和IP存不同字段名称的。
但是flutter似乎不验证IP字段的,所以使用IP访问会出现hostname不匹配的问题。
这事搞得我曾经怀疑人生,IP明明已经列进证书,Androd原生代码、PC浏览器、curl都没问题。
flutter就是不行,最后通过把IP列进域名字段就正常了。不按套路出牌,也不说明,真是累死人。
Create your own Certificate Authority (CA) using OpenSSL