日本は地震が多いですね。その割には情報を入手する手段が少ない気がします。
テレビでは震度5弱以上予想時のみ提供されますが、震度4以下の場合には事後の提供のみです。
提供してもらえないなら自分で入手しましょう。
(毎回 Qiita 記事の頭の文章が適当になってしまう)
なお、記事の最後に わざわざ自分で電文を受信して解析する必要がない方法
も紹介します。
免責事項
筆者は現在この記事で紹介する方法は 使用していません
。今後使えなくなっても責任は負いかねます。
参考にする場合は自己責任でお願いします。
環境
- 安定したネットワーク環境 (1Mbps 以下でも接続を維持できればOK)
- C# 開発環境
- Windows 10
- WeatherNews.jp 有料会員
流れをざっくりと説明
気象庁 -> WeatherNews.jp -> 利用者
WeatherNews.jp -> 利用者 の間は TCPSocket を使用します。
プログラム
簡単にサンプルで作成したプログラムを載せます。自由に改変や修正を加えてください。
途中の正規表現は即席なのでもっと良いパターンがあればコメントでお願いします。
また、 WNI が緊急地震速報を送信するサーバーの IP アドレスは http://lst10s-sp.wni.co.jp/server_list.txt に記述されていますが、どれでもOKです。
選択するサーバーによっては遅延がかなり酷く、平気で1分以上遅れたりする場合があります。
なのでサーバーガチャで勝利してください。
「ここ速かったよ!」とかありましたらコメントでお願いします。(使っていないけど)
あ、死活管理は適宜実装してください。
public class WniClient : IDisposable {
private Socket _socket;
private const int BufferSize = 1024;
private readonly byte[] _buffer = new byte[BufferSize];
public async Task ConnectAsync(string mailAddress, string passWord)
{
// パスワードを MD5 に変換
var passWordByte = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(passWord));
// MD5 に変換すると byte[] になるため string に変換
var passWordStr = BitConverter.ToString(passWordByte).ToLower().Replace("-", "");
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(new IPEndPoint(IPAddress.Parse(await GetServerIpAsync()), 80));
// 認証情報を送信
_socket.Send(new UTF8Encoding().GetBytes($"GET /login HTTP/1.1\r\nX-WNI-Account: {mailAddress}\r\nX-WNI-Password: {passWordStr}\r\n\r\n"));
// データ受信時にイベント発火
_socket.BeginReceive(_buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, _socket);
}
private static async Task<string> GetServerIpAsync()
{
using var c = new HttpClient();
var servers = (await c.GetStringAsync("http://lst10s-sp.wni.co.jp/server_list.txt").ConfigureAwait(false)).Split('\n');
var rdm = new Random();
var server = servers[rdm.Next(0, servers.Length - 1)];
return server.Split(':')[0];
}
public void Disconnect() => _socket.Disconnect(false);
public void Dispose() => _socket.Close();
private void ReceiveCallback(IAsyncResult asyncResult)
{
var socket = (Socket)asyncResult.AsyncState;
if (socket == null) return;
int byteSize;
try
{
byteSize = socket.EndReceive(asyncResult);
}
catch (Exception ex)
{
OnException?.Invoke(ex);
return;
}
if (byteSize < 1) return;
var res = Encoding.UTF8.GetString(_buffer, 0, byteSize);
if (res.Contains("X-WNI-ID: Data"))
{
res = new string(res.Replace("\n", " ").Replace("\r", " ").Replace(" ", " ").Where(x => !char.IsControl(x)).ToArray());
var mc = new Regex("3([0-9/]{1}) ([0-9/]{2}) ([0-9/]{2}) ([0-9/]{12}) C([0-9/]{2}) ([0-9/]{12}) ND([0-9/]{14}) NCN([0-9A-Z/]{3}) JD([0-9/]{14}) JN([0-9/]{3}) ([0-9/]{3}) ([N0-9/]{4}) ([E0-9/]{5}) ([0-9/]{3}) ([0-9/]{2}) ([0-9/+-]{2}) RK([0-9/]{5}) RT([0-9/]{5}) RC([0-9/]{5}) (.*?)9999=", RegexOptions.None).Matches(res);
foreach (Match m in mc) OnReceiveData?.Invoke(m.Value.Trim());
}
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, socket);
}
public delegate void ReceiveEventHandler(string receiveData);
public event ReceiveEventHandler OnReceiveData;
public delegate void OnExceptionEventHandler(Exception exception);
public event OnExceptionEventHandler OnException;
}
private static async Task Main()
{
using var client = new WniClient();
// 受信したら OnReceiveData が発火し、電文が渡される
client.OnReceiveData += Console.WriteLine;
await client.ConnectAsync("[メールアドレス]", "[パスワード]");
Console.ReadLine();
client.Disconnect();
}
まとめ
The Last 10-Second
で使用されている緊急地震速報配信サーバーを利用する方法を紹介しました。
とにかく遅延が酷いです。調子がいい時は3秒遅れ程度や遅延無しで配信されます。
速いサーバーを見つけた方は共有しましょう。
楽な方法
手前味噌ですが https://api.iedred7584.com/eew/ を使ってください。(宣伝)