お久しぶりです、竹内です。
あれからプロセス間通信を用いて、
ログを表示するサンプルを作成してみました。
動作的には以下のようになっています。
C++アプリ
↓ TCPソケット通信
node.js
↓ webソケット
ブラウザ
もう少し細かい挙動を説明しますと、今回作成したプログラムは、
(1)C++アプリから受け取ったメッセージをnode.jsを保存
(2)node.jsは2秒おきにC++アプリから受け取ったメッセージをブラウザに送信
という動作をしています。
今回は(2)の一定時間置きにブラウザに対してメッセージを送信する、
というところで詰まってしまいました。
このコードを動作させると、コンソールメッセージから
タイムインターバルのコールバック関数が呼ばれていることは分かりますが、
sendUTF()が呼ばれたタイミングでブラウザ側にメッセージが送信されません。
また、ブラウザとnode.jsの接続が切れたタイミングで、sendUTF()にたまっていたメッセージが
全て送信されていました。
定期的にイベントを呼び出している部分は、wsServer.on('request')のsetInterval()になります。
今回、質問をさせて頂きたいのは、以下の2点です。
(1)setIntervalでconn.sednUTF()を呼び出してもサーバ側にすぐに送信されない理由
(2)サーバとブラウザの接続が切れたタイミングで今までのメッセージが全送信される理由
このプログラムはC++アプリがなくても、受け取りメッセージにはデフォルト値が格納されているため
問題なく動作します。
********************************************
node.jsコード
serve.js
********************************************
//* Grobal Value
var net = require('net');
var http = require('http');
var WebSocketServer = require('websocket').server;
var AcceptConsoleMessagePort = 8124;
var WebSocketServerListenPort = 8080;
var index = require('fs').readFileSync('logview.html');
var mes = 'default message';
//Accept Console Message Server
var acceptMessageServer = net.createServer(function(socket) { //'connection' listener
console.log('Accept Message Server connected');
socket.on('end', function() {
console.log('Accept Message Server disconnected');
});
socket.on('data', function(data) {
mes = data.toString();
console.log('Accept Data Process :' + mes);
});
});
//Listen
acceptMessageServer.listen(AcceptConsoleMessagePort, function() {
console.log('Accept Message Server Listen : ' + AcceptConsoleMessagePort );
});
//Websocket Listen Server
var server = http.createServer(function(req, res) {
if (req.url === '/') {
res.writeHead(200, { 'content-type': 'text/html'});
res.end(index);
} else {
res.writeHead(404);
res.end();
}
});
//Listen
server.listen(WebSocketServerListenPort, function() {
console.log('Listening on ' + WebSocketServerListenPort);
});
//Websocket Server
var wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
});
wsServer.on('request', function(req) {
var conn = req.accept('stdin-to-ws', req.origin);
console.log((new Date()) + ' Peer ' + conn.remoteAddress + ' connected.');
//この部分で定期的にブラウザへメッセージ送信をしている。
setInterval(function(){
console.log('start sned client');
conn.sendUTF(mes);
console.log('end sned client : ' + mes);
},2000);
conn.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + conn.remoteAddress + ' disconnected.');
});
});
********************************************
クライアント側コード
logview.html
********************************************
<!DOCTYPE html>
<html>
<head>
<title>logview</title>
</head>
<body>
<div id="msg"></div>
<script>
var msg = document.getElementById("msg");
var ws = new WebSocket("ws:localhost:8080/", "stdin-to-ws");
ws.onmessage = function(e) {
var data = document.createElement("div");
data.innerHTML = e.data;
msg.appendChild(data);
};
</script></body></html>
********************************************
C++アプリのコード
main.cpp
********************************************
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
SOCKET InitializeClientWinsock(LPSTR lpszServerName, LPSTR lpszPort);
//---------------------------------------------------------
//
// main
//
//---------------------------------------------------------
void main() {
char mes[256]="gundamX";
char hostName[256]="localhost";
char port[16]="8124";
bool loopFlag = true;
SOCKET soc;
printf("Welcome to ScarletRain\n");
printf("Start Connecting\n");
soc=InitializeClientWinsock("localhost","8124");
printf("Connection Complate\n");
while(loopFlag) {
int ret;
scanf("%s",mes);
ret = send(soc,mes,strlen(mes),0);
printf("send %d byte success\n",ret);
}
printf("Bye\n");
}
//---------------------------------------------------------
//
// ソケットの初期化(クライアント)
//
//@param LPSTR lpszServerName 接続先サーバのホスト名
//@param LPSTR lpszPort 接続先サーバポート番号
//@return SOCKET サーバのリッスンソケット
//---------------------------------------------------------
SOCKET InitializeClientWinsock(LPSTR lpszServerName, LPSTR lpszPort)
{
WSADATA wsaData;
ADDRINFO addrHints;
LPADDRINFO lpAddrList;
SOCKET soc;
//ソケットのスタートアップ
WSAStartup(MAKEWORD(2, 2), &wsaData);
//ソケット接続情報設定
ZeroMemory(&addrHints, sizeof(addrinfo));
addrHints.ai_family = AF_INET;
addrHints.ai_socktype = SOCK_STREAM;
addrHints.ai_protocol = IPPROTO_TCP;
//ホスト名からIPを取得
if (getaddrinfo(lpszServerName, lpszPort, &addrHints, &lpAddrList) != 0) {
MessageBox(NULL, TEXT("ホスト情報からアドレスの取得に失敗しました。"), NULL, MB_ICONWARNING);
WSACleanup();
return INVALID_SOCKET;
}
//ソケットの作成
soc = socket(lpAddrList->ai_family, lpAddrList->ai_socktype, lpAddrList->ai_protocol);
if (connect(soc, lpAddrList->ai_addr, (int)lpAddrList->ai_addrlen) == SOCKET_ERROR) {
int nError = WSAGetLastError();
if (nError == WSAECONNREFUSED)
MessageBox(NULL, TEXT("サーバーがリッスンしていません。"), NULL, MB_ICONWARNING);
else if (nError == WSAEHOSTUNREACH)
MessageBox(NULL, TEXT("サーバーが存在しません。"), NULL, MB_ICONWARNING);
else
MessageBox(NULL, TEXT("サーバーへの接続が失敗しました。"), NULL, MB_ICONWARNING);
freeaddrinfo(lpAddrList);
closesocket(soc);
WSACleanup();
return INVALID_SOCKET;
}
freeaddrinfo(lpAddrList);
return soc;
}
2013年4月7日日曜日 17時04分24秒 UTC+9 竹内佑介: