// server.dart
import 'dart:io';
import 'dart:convert';
class ChatRoom {
int key = 0;
static int sn = 0;
static Map<int, Socket> sockets = { };
void broadcast(List<int> data) {
sockets.forEach((id, session) {
if (key != id) session.add(utf8.encode('id$key:>${utf8.decode(data)}'));
});
}
void relay(List<int> data) async {
String text = utf8.decode(data).trim();
if (text == 'quit') {
print('relay: $text');
final session = sockets.remove(key);
await session?.close();
}
broadcast(data);
}
void shutdown( ) {
sockets.remove(key);
broadcast(utf8.encode('bye!\n'));
print('id$key leave, remain ${sockets.length}');
}
ChatRoom (Socket session) {
key = ++sn;
session .. add(utf8.encode('id${key} welcome!\n')) .. listen(
relay,
onDone: shutdown,
onError: (_) => session.close()
);
sockets[key] = session;
print('id$key join [total ${sockets.length}]');
}
}
void main( ) {
int port = 8080;
print("Chat room at $port");
ServerSocket.bind(InternetAddress.anyIPv4, port).then((ServerSocket server) {
server.listen((socket) => ChatRoom(socket));
});
}
使用 dart VM 來跑: dart server.dart, 之後就可以用 telnet 127.0.0.1 8080 讓客戶端連進聊天室, 只是 linux 上的 telnet client 在中文編/解碼上, 雖然接收時解中文碼沒問題, 但傳送時編成的中文碼可能會有問題, 幸好用 dart 語言編寫相同功能的 telnet 終端機不是難事:
// client.dart
import 'dart:io';
import 'dart:convert';
void main(List<String> args) async {
String ip = (args.length > 0) ? args[0] : 'localhost';
int port = (args.length > 1) ? int.parse(args[1]) : 8080;
Socket session = await Socket.connect(ip, port);
session.listen (
(dynamic data) => print((data is String) ? data : utf8.decode(data).trim()),
onDone: ( ) => exit(0),
onError: (_) => session.close()
);
stdin.listen (
(List<int> data) {
try {// print(data);
if (utf8.decode(data).trim() == 'quit') throw 'user quit';
else session.add(data);
} catch(e) {
print('stdin: $e, $data');
session.close();
exit(0);
}
}
);
}
同樣用 dart VM 來跑: dart client.dart
2022年11月27日 星期日
用 dart 語言寫簡單的 SocketServer 聊天室
2022年11月25日 星期五
使用 crypto 產生密鑰並自我簽證
// sudo apt-get install libcrypto
// g++ genrsa.c -lcrypto && ./a.out
// genrsa.c
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <stdio.h>
int main( ) {
int nbits = 2048;
RSA *rsaKey = RSA_new();
BIGNUM *bignF4 = BN_new();
BN_set_word(bignF4, 0x10001);// bignF4 = 65537
if (RSA_generate_key_ex(rsaKey, nbits, bignF4, NULL)) {
long days = 365;
unsigned char* subj[3] = {
(unsigned char *)"TW",
(unsigned char *)"SELF",
(unsigned char *)"0.0.0.0"
};
X509 *certify = X509_new();
X509_set_version(certify, 2);// Ver 3
ASN1_INTEGER_set(X509_get_serialNumber(certify), 1);
X509_gmtime_adj(X509_get_notBefore(certify), 0);
X509_gmtime_adj(X509_get_notAfter(certify), days * 86400);
X509_NAME *subjName = X509_get_subject_name(certify);
X509_NAME_add_entry_by_txt(subjName, "C" , MBSTRING_ASC, subj[0], -1, -1, 0);
X509_NAME_add_entry_by_txt(subjName, "O" , MBSTRING_ASC, subj[1], -1, -1, 0);
X509_NAME_add_entry_by_txt(subjName, "CN", MBSTRING_ASC, subj[2], -1, -1, 0);
X509_set_issuer_name(certify, subjName);
EVP_PKEY *keyPair = EVP_PKEY_new();
EVP_PKEY_assign_RSA(keyPair, rsaKey);
X509_set_pubkey(certify, keyPair);
X509_sign(certify, keyPair, EVP_sha1());
FILE *fout = fopen("private.pem", "wb");
PEM_write_PrivateKey(fout, keyPair, NULL, NULL, 0, NULL, NULL);
fclose(fout);
EVP_PKEY_free(keyPair);
fout = fopen("certify.pem", "wb");
PEM_write_X509(fout, certify);
fclose(fout);
X509_free(certify);
}
BN_free(bignF4);
RSA_free(rsaKey);
return 0;
}
2022年11月24日 星期四
關於 Flutter 3.3.x 黑畫面問題
在 Linux 上使用 Flutter 3.0.5 版本, 寫 linux 的處理畫面(gui)小程式, 一直以來都沒什問題, 更新到 3.3.6 版, 就是無法繪圖, 即使增開一個測試程式: flutter create test && cd test && flutter run, 也看不到點擊畫面, 只好延用 3.0.5 版, 到今天(2022.11.25), Flutter 早已更新到 3.3.9 版, 下載的 stable 版本仍然不正常, 於是就上網路查, 有人說目前 3.3.x stable 版都有此問題, 切換到 channel master 就可以了, 好奇之下, 開啟終端機, 下個命令:
flutter channel master
畫面真的恢復了, 試試把它切回 flutter channel stable, 還真的不正常, 結論就是目前下載的 flutter 3.3.9 版仍要再切到 flutter master channel, 接著讓它上網自動更新, 之後 linux 上處理畫面的程式就能正常運作.
2022年11月23日 星期三
20 幾行的 http 伺服器(node js)
// http.js
const http = require('http');
const fs = require('fs');
const objHtml = {'Content-Type' : 'text/html;charset=utf-8'};
const uService = (req, reply) => {
const filename = (req.url == '/') ? './index.html' : `.${req.url}`;
if (! fs.existsSync(filename)) {// console.log(filename);
reply.writeHead(404, objHtml);
reply.write('<!DOCTYPE html><html><body>Not Found<body></html>');
reply.end();
return;
}
const mimeType = filename.endsWith('.html') ? objHtml :
filename.endsWith('.css') ? {'Content-Type' : 'text/css'} :
filename.endsWith('.js') ? {'Content-Type' : 'application/javascript'} :
{'Content-Type' : 'application/octet-stream'};
reply.writeHead(200, mimeType);
fs.createReadStream(filename).pipe(reply);
}
const port = 8080;
console.log(`http://0.0.0.0:${port}/`);
http.createServer(uService).listen(port);
使用 nodejs 來跑: node http.js, 並用瀏覽器瀏覽網址 http://127.0.0.1:8080/index.html
改用 dart 語言來寫:
// http.dart
import 'dart:io';
final objHtml = ContentType('text', 'html', charset: 'UTF-8');
final uService = (HttpRequest req) {
final reply = req.response;
final filename = (req.uri.path == '/') ? './index.html' : '.${req.uri.path}';
final file = File(filename);
if (! file.existsSync()) {
reply .. statusCode = 404 ..
headers.contentType = objHtml ..
write('<!DOCTYPE html><html><body>Not Found<body></html>') ..
close();
return;
}
reply .. statusCode = 200 ..
headers.contentType = RegExp(r'(\.htm|\.html)$').hasMatch(filename) ? objHtml :
RegExp(r'\.css$').hasMatch(filename) ? ContentType('text', 'css') :
RegExp(r'\.js$').hasMatch(filename) ? ContentType('application', 'javascript') :
ContentType('application', 'octet-stream') ..
headers.contentLength = file.lengthSync();
file.openRead().pipe(reply);
};
main() {
final port = 8080;
print("http://0.0.0.0:${port}/");
HttpServer.bind(InternetAddress.anyIPv4, port).then((http)=>http.listen(uService));
}
使用 dart 來跑: dart http.dart, 並用瀏覽器瀏覽網址 http://127.0.0.1:8080/index.html
2022年11月5日 星期六
玩 Arch Linux
1. 官網下載 Iso 檔 https://archlinux.org/download/, 目前 2022.11.01 版支援 Kernel 6.06, youtube 有許多影片教導重頭至尾的安裝步驟
2. 我用 pacstrap下載以下套件,就足以實現一套完整的中文 linux x11 桌面系統在 VirtualBox 上跑:
base linux linux-firmware base-devel linux-headers grub dosfstools squashfs-tools xorriso efibootmgr os-prober gdisk parted dhcpcd networkmanager network-manager-applet dialog wireless_tools wpa_supplicant openssh git virtualbox-guest-utils xorg lightdm lightdm-gtk-greeter mate mate-extra xorg-server wqy-bitmapfont wqy-zenhei wqy-microhei wqy-microhei-lite opendesktop-fonts ttf-arphic-ukai ttf-arphic-uming pulseaudio pulseaudio-alsa pavucontrol materia-gtk-theme papirus-icon-theme firefox xed geany gcin vim
後記:
1. 下載並安裝完後再將 /var/cache/pacman/pkg 刪除可以能節省 1G 左右空間
2. 假設 EFI filesystem 在 /dev/sda1, 安裝 grub bootloader 到 /dev/sda2:
mkdir /mnt/efi && mkdir /mnt/boot
mount /dev/sda1 /mnt/efi && mount /dev/sda2 /mnt/boot
grub-install --target=x86_64-efi --efi-directory=/mnt/efi --boot-directory=/mnt/boot --bootloader-id=grub /dev/sda
Linux mint 玩 waydroid 一些心得
1. 目前使用 linux mint 22.1 作業系統可以順利跑起來, 可上官網去下載, 並安裝到硬碟. 2. 安裝 waydroid 可上網站 https://docs.waydro.id 參考看看: https://docs.waydro.id/usage/inst...
-
1. 上 Firebase 網站 註冊啟用 Firebase : https://firebase.google.com/ 2. 進入 Firebase Console 註冊開啟新專案 : https://console.firebase.google.com/...
-
Flutter 讓人很容易短時間就能開發出 app, 關鍵在於他開發了很多種小部件稱為 Widget, 將Widget 組合起來就是一個 app. 所謂 部 件(Widget)就是一個可以呈現在螢幕上的視覺系 物 件,幾乎可以說 Flutter 每個物件都是 部 件. 開發者透...