2021年6月16日水曜日

webSocket通信が必要になる度に接続するサンプル

webSocketの同時接続数には制限があるらしいです。
1つの接続を各機能で共有してやりくりする方法を昨日投稿しましたが、各機能が必要としたタイミングで接続して用が済み次第 切断する、というバージョンも作成してみました。



webSocketの同時接続数の制限について参照した記事は以下です。
IEのwebsocet同時接続数は6



import { listenAndServe } from "https://deno.land/std/http/server.ts";
export async function httpサーバを起動(httpリクエスト処理: any){
const port = await 空いてるport番号を返す()
const server = listenAndServe({ port: port }, async (req)=> { httpリクエスト処理(req) });
console.log(`HTTP webserver running. Access it at: http://localhost:` + port + `/`)
ブラウザ起動(port)
}
function ブラウザ起動(port: number){
Deno.run({cmd:['cmd', '/C start http://localhost:'+port]})
}
async function 空いてるport番号を返す(): Promise<number>{
let pathBat = await 一時ファイルを作成('netstat -na | find "%~1"')
if(pathBat.match(/[  ]/)){
throw new Error('一時ファイルのPathにスペースが含まれています。\n'+pathBat+'\nDeno.runでは「"」の記号の前に「\\」が挿入されてしまうため、使用できません。')
}
for(let port=49152; port<=65535 ;port++){
const p = Deno.run({cmd:['cmd', '/C', 'chcp 65001 & '+pathBat+' ' + port], stdout:'piped'})
const o = await p.output()
const text = new TextDecoder().decode(o)
// console.log('text:\n'+text)
if(text.indexOf(':'+port)==-1){
Deno.remove(pathBat)
return port
}
}
throw new Error('throw from port num search')
}
async function 一時ファイルを作成(value:string){
const path = await Deno.makeTempFile({prefix: 'deno_tmp', suffix:'.bat'})
await Deno.writeTextFile(path, value)
return path
}
import * as path from "https://deno.land/std@0.97.0/path/mod.ts"; // pathResolver
import { webSocket接続 } from './webSocket接続.ts'
export async function httpリクエスト処理(request: any){
if(request.method != 'GET'){return}
console.log('url:[' + request.url + ']')
let url = request.url
if(url=='/ws'){return webSocket接続(request)}
if(url=='/'){ url = './index.html' }
if(url.indexOf('/')==0){ url = '.' + url }
url = 絶対Pathに変換(url)
const ファイルの有無 = await fileExists(url)
if(!ファイルの有無){
return request.respond({ status: 404 })
}
const file = await Deno.open(url);
request.respond({
status: 200,
headers: new Headers({"content-type": 拡張子2contentType(url)}),
body: file
});
}
function pathResolver(meta: ImportMeta): (p: string) => string {
return (p) => path.fromFileUrl(new URL(p, meta.url))
}
const 絶対Pathに変換 = pathResolver(import.meta);
function 拡張子2contentType(url: string):string{
if(url.match(/\.htm(l?)$/)){return 'text/html'}
if(url.match(/\.css$/)){return 'text/css'}
if(url.match(/\.js$/)){return 'text/javascript'}
return ''
}
async function fileExists(filePath: string): Promise<boolean> {
try {
await Deno.lstat(filePath);
return true;
} catch (err) {
if (err instanceof Deno.errors.NotFound) {
return false;
}
throw err;
}
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>webSocket接続の維持</title>
</head>
<body>
<input id=inp style="width:100%">
<textarea id=ta style="width:100%;height:200px">D:\abc\de f\1.ts</textarea>
</body>
<script src="./Read.js"></script>
<script src="./webSocket_ブラウザ側.js"></script>
<script>
inp.onchange = async function(){
const path = this.value
if(!path){return}
Read(path).then((txt)=>{ ta.value = txt })
}
</script>
</html>
view raw index.html hosted with ❤ by GitHub
export async function JSONレシーバー(ws:any, msg:string, clients:Map<number, any>){
const obj = JSON.parse(msg)
console.log('msg['+msg+']')
if(obj.readTextFile){
const text = await Deno.readTextFile(obj.path)
return 返信(ws, text)
}
}
function 返信(ws:any, msg:any){
const str返信用 = JSON.stringify(msg)
ws.send(str返信用)
}
// --allow-run --allow-net --allow-read --allow-write
import { httpサーバを起動 } from './httpサーバを起動.ts'
import { httpリクエスト処理 } from './httpリクエスト処理.ts'
httpサーバを起動(httpリクエスト処理)
view raw main.ts hosted with ❤ by GitHub
function Read(path){
return new Promise(function (resolve) {
webSocket通信({readTextFile:true, path}).then(resolve)
})
}
view raw Read.js hosted with ❤ by GitHub
function webSocket通信(msg){
return new Promise(function (resolve) {
const ws = new WebSocket(`ws://${location.host}/ws`)
ws.onopen = () => {
ws.send(JSON.stringify(msg))
}
ws.onmessage = ({data}) => {
const obj = JSON.parse(data)
resolve(obj)
ws.close()
}
})
}
import {
WebSocket,
isWebSocketCloseEvent,
} from "https://deno.land/std/ws/mod.ts";
import { JSONレシーバー } from "./JSONレシーバー_deno側.ts"
export async function webSocketリクエスト処理(ws: WebSocket): Promise<void> {
const id = ++clientId;
clients.set(id, ws);
console.log(`[${id}]番目の接続 open`);
for await (const msg of ws) {
if (typeof msg === "string") {
JSONレシーバー(ws, msg, clients)
continue
} else if (isWebSocketCloseEvent(msg)) {
console.log(`[${id}]番目の接続 close`);
clients.delete(id);
break;
}
}
}
const clients = new Map<number, WebSocket>();
let clientId = 0;
import {
acceptWebSocket,
acceptable,
} from "https://deno.land/std/ws/mod.ts";
import { webSocketリクエスト処理 } from './webSocketリクエスト処理.ts'
export function webSocket接続(request: any):void{
console.log('webSocket接続')
if(!acceptable(request)){return console.log('webSocket接続 not acceptable')}
acceptWebSocket({
conn: request.conn,
bufReader: request.r,
bufWriter: request.w,
headers: request.headers,
}).then(webSocketリクエスト処理);
}



上記ソースの実行結果が以下。

0 件のコメント:

コメントを投稿