LoginSignup
7
3

More than 3 years have passed since last update.

緊急地震速報の生電文を受信しよう

Last updated at Posted at 2020-03-17

日本は地震が多いですね。その割には情報を入手する手段が少ない気がします。
テレビでは震度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分以上遅れたりする場合があります。
なのでサーバーガチャで勝利してください。
「ここ速かったよ!」とかありましたらコメントでお願いします。(使っていないけど)

あ、死活管理は適宜実装してください。

WniClient.cs
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;
}
Main.cs
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/ を使ってください。(宣伝)

7
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3