コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

ソケットプログラミング(UDP)

LinuxUDPによる通信を行うサンプルプログラム。

この手の例はGoogle先生で検索すれば沢山でてくるけど、システムコールのリターン値を見てなかったり、openに対応するcloseをしていない例が多いことに気付くと思う。

もちろん動かすことだけ考えたら気にする必要ないし、この例も完璧とは言えないけど、出来るだけ丁寧な処理を書くことを心がけるようにしたい。



udp_client.c

#include "local.h"

int main(void)
{
    udpSocket_t udp;

    udp.sfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (udp.sfd < 0) {
        PERROR("socket()");
        goto error_end;
    }

    udp.addr.sin_family = PF_INET;
    udp.addr.sin_port = htons(PORTNO);
    udp.addr.sin_addr.s_addr = inet_addr(LOCALHOST);

    char msgbuf[] = "HELLO WORLD\n";
    ssize_t snd = sendto(udp.sfd, msgbuf, sizeof(msgbuf), 0,
                         (struct sockaddr *)&udp.addr, sizeof(udp.addr));
    if (snd < 0) {
        PERROR("sendto()");
        goto close_end;
    }

close_end:
    close(udp.sfd);
error_end:

    return 0;
}


udp_server.c

#include "local.h"

int main(void)
{
    udpSocket_t udp;
    char msgbuf[MSGBUF_SIZE] = {0};

    udp.sfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (udp.sfd < 0) {
        PERROR("socket()");
        goto error_end;
    }

    udp.addr.sin_family = PF_INET;
    udp.addr.sin_port = htons(PORTNO);
    udp.addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(udp.sfd,
             (struct sockaddr *)&udp.addr,
             sizeof(udp.addr)) < 0) {

        PERROR("bind()");
        goto close_end;
    }

    ssize_t rcv = recvfrom(udp.sfd, msgbuf, sizeof(msgbuf), 0,
                           (struct sockaddr*)&udp.addr, &udp.addrlen);
    if (rcv < 0) {
        PERROR("recvform()");
        goto close_end;
    }

    fprintf(stdout, "%s", msgbuf);

close_end:
    close(udp.sfd);
error_end:

    return 0;
}


local.h

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define PORTNO  (50001)
#define MSGBUF_SIZE (4096)
#define LOCALHOST "127.0.0.1"

#define PERROR(X) \
{\
    char _strerr[64] = {0};\
    int errcode = errno;\
    \
    strerror_r(errcode, _strerr, sizeof(_strerr));\
    printf(X" failed(%d:%s)\n", errcode, _strerr);\
}

typedef struct {
    int                 sfd;
    struct sockaddr_in  addr;
    socklen_t           addrlen;
} udpSocket_t;

実行例

$ gcc udp_client.c -o client
$ gcc udp_server.c -o server
$ ./server 
$ ./client   #別端末から実行
HELLO WORLD
$

Linuxでシグナル捕捉

使い方をすぐに忘れるsigactionでシグナルを捕捉する方法。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

static volatile sig_atomic_t RecvSigno = 0;

void signal_handler(int signo)
{
    RecvSigno = signo;
}

int main(void)
{
    struct sigaction sigact = {
        .sa_handler = signal_handler,
        .sa_flags = 0,
    };
    uint8_t siglist[] = {
        SIGINT,
        SIGTERM,
        SIGQUIT,
        SIGCHLD,
        SIGPIPE,
    };

    sigemptyset(&sigact.sa_mask);

    for(int entry = 0; entry < sizeof(siglist); entry++) {
        if(sigaction(siglist[entry], &sigact, NULL) < 0) {
            int errcode = errno;
            char strerr[64] = {0};
            strerror_r(errcode, strerr, sizeof(strerr));
            printf("sigaction() failed(%s)\n", strerr);
        }
    }

    while (1) {
        if (RecvSigno != 0) {
            printf("Recieved signal(%d)\n", RecvSigno);
            RecvSigno = 0;
        }

        sleep(1);
    }

    return 0;
}

実行結果

$ gcc -o signal -std=gnu99 signal.c
$ ./signal
^CRecieved signal(2)   # Ctrl+C実行
Hangup                 # 別端末からkill -SIGHUP <pid>を実行
$


新規のプログラムはsignal(2)ではなくsigaction(2)を使うことが推奨される。
シグナルの扱いについてはMan page of SIGNAL参照。

Teratermマクロでカウンタ表示

Teratermマクロで実行回数を表示する。


カウンタ表示マクロ(counter.ttl)

; グローバル変数
Count = 0
true = 1
false = 0

; 以下、dateコマンドを無限に繰り返す
while true
  call show_counter
  sendln "date"
  wait ']$'
  pause 1
endwhile

; カウンタの表示
:show_counter
sprintf2 str "%d 回目" Count
statusbox str "カウンタ"
Count = Count + 1
return


実行結果
f:id:segmentation-fault:20170218200125p:plain




画面ログに残すだけなら下記。

1秒毎にカウントアップ

count = 1 
true = 1

while true
  int2str counts count
  sendln '##### ' counts ' times ' 
  pause 1
  count = count + 1 
endwhile


実行結果

$ ##### 1 times
$ ##### 2 times
$ ##### 3 times
$ ##### 4 times
$ ##### 5 times





PowerShellで某コンビニの入店音ぽい音

WindowsPowerShellbeep音を出す。
折角なのであのメロディーの再現にトライしてみた。


実行に必要な準備


実行するスクリプト(enter.ps1)

# a certain convenience store

[Console]::Beep(1479, 400) # F#5
[Console]::Beep(1174, 400) # D5
[Console]::Beep(880,  400) # A4
[Console]::Beep(1174, 400) # D5
[Console]::Beep(1318, 400) # E5
[Console]::Beep(1760,1000) # A5

[Console]::Beep(1318, 400) # E5
[Console]::Beep(1479, 400) # F#5
[Console]::Beep(1318, 400) # E5
[Console]::Beep(880,  400) # A4
[Console]::Beep(1174, 800) # D5


実行結果

PS C:'\pass'>  Get-ExecutionPolicy
RemoteSigned
PS C:'\pass'> 
PS C:'\pass'> .\enter.ps1
(演奏中)


クオリティはご愛嬌ということで(笑)

Tone.jsで音を鳴らしてみる

Tone.jsを使って簡単な演奏をしてみた。
今回は4分音符で単調なメロディーを繰り返すだけ。

doremi.html

<!-- index.html -->
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>サウンド</title>
</head>

<body>
    <button id="play">PLAY</button>
    <button id="stop">STOP</button>
    <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
    <script src="https://cdn.rawgit.com/Tonejs/Tone.js/4c2cf070/build/Tone.js"></script>
    <script>
      var bell = new Tone.Synth().toMaster();
      var bellPart = new Tone.Sequence(function(time, note){
          bell.triggerAttackRelease(note, "4n", time);
      }, ["C4", "D4", "E4", "F4", "E4", "D4","C4", "4n"]).start(0);
 
      Tone.Transport.bpm.value = 120;

      $("#play").click(function() {
        Tone.Transport.start()
      });
      
      $("#stop").click(function() {
        Tone.Transport.stop()
      });
    </script>
</body>

実行結果
f:id:segmentation-fault:20170217010424p:plain


今のところ4分音符の使い方しかわからず。
途中に2分音符や8分音符を挟むにはどうすればよいのだろう。

X11で始めるGUIプログラミング

いまどきX11でプログラム書くことがあるかは知らないけど、
凄い昔にLinuxGUIのプログラミングにトライしたときのサンプルコードを見つけたので掲載。
現代はQtとか使うのかな。

事前準備

$ sudo yum -y install libX11*


x11.c

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <math.h>

#define N 8

unsigned long GetColor( Display* dis, char* color_name )
{
    Colormap cmap;
    XColor near_color, true_color;

    cmap = DefaultColormap( dis, 0 );
    XAllocNamedColor( dis, cmap, color_name, &near_color, &true_color );
    return( near_color.pixel );
}


int main( void )
{
    Display* dis;
    Window win;
    XSetWindowAttributes att;
    GC gc;
    XEvent ev;

    int x[N],y[N];
    int i,j;

    dis = XOpenDisplay( NULL );
    win = XCreateSimpleWindow( dis, RootWindow(dis,0), 100, 100,
      256, 256, 5, WhitePixel(dis,0), BlackPixel(dis,0) );

    att.backing_store = WhenMapped;
    XChangeWindowAttributes( dis, win, CWBackingStore, &att );

    XSelectInput( dis, win, ExposureMask );
    XMapWindow( dis, win );

    do{
        XNextEvent( dis, &ev);
    }while( ev.type != Expose );

    gc = XCreateGC( dis, DefaultRootWindow(dis), 0, 0 );
    XSetForeground( dis, gc, GetColor( dis, "green")  );


    for( i=0 ; i < N ; i++ ){
        x[i] = (int)(128*cos(2*M_PI*i/N))+128;
        y[i] = (int)(128*sin(2*M_PI*i/N))+128;
    }

    for( i=0 ; i < N ; i++ ){
        for( j=i+1 ; j < N ; j++ ){
            XDrawLine( dis, win, gc, x[i], y[i], x[j], y[j] );
        }
    }

    XFlush( dis );

    getchar();
    XDestroyWindow( dis , win );
    XCloseDisplay( dis );

    return(0);
}


実行結果

$ gcc -o x11 x11.c -I/usr/include -L/usr/lib -lX11 -lm
$ ./x11


f:id:segmentation-fault:20170215233702p:plain

URLを指定して開いたページをPDFで保存する

IEで特定のページを開く→ 仮想プリンタでPDF印刷という作業を繰り返したい人向け。

[作業の流れ]

  1. 仮想プリンタ(BullzipやPDF reDirect等)をインストールして通常使うプリンタに設定する。
  2. ExcelでURLのリストを作り、マクロにPDF化するプログラムを記載して実行。


PDF_PRINT.xlsm
f:id:segmentation-fault:20171125225446p:plain

VBAコード

'Sleepを使うためライブラリを呼び出し
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Sub PRINT_PDF()

  'URLリスト範囲
  Const URL_LIST_HEAD = 1
  Const URL_LIST_TAIL = 4
  Const URL_LIST_ROW = 1

  Dim UrlEntry As Long
  
  'URL数分繰り返し
  For UrlEntry = URL_LIST_HEAD To URL_LIST_TAIL
    'URLを指定してPDFで印刷する
    Call URL2PDF(Cells(UrlEntry, URL_LIST_ROW))
  Next UrlEntry

End Sub


Function URL2PDF(URL As String)
    
  'iexplore.exe起動
  Set IE = CreateObject("InternetExplorer.Application")
  
  'ブラウザ表示
  IE.Visible = True

  'URL指定したページを表示
  IE.Navigate URL
  
  'ページの読み込みが完了するまで待機
  Do Until IE.Busy = False
      Sleep 250
  Loop

  'デフォルトのプリンタ(今回はPDF出力する仮想プリンタ)で印刷実行
  'IE.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER
  IE.ExecWB 6, 2
  
  'ENTER, ALT+F4(閉じる)キーの送信用
  Set Sh = CreateObject("WScript.Shell")
  
  '適度なwait
  Sleep 3000

  '仮想プリンタの印刷ボタンをポチッとな
  Sh.SendKeys ("{ENTER}")

  '適度なwait
  Sleep 10000
  
  '閉じるボタン(ショートカットキー)(必要なら)
  'Sh.SendKeys ("%" + "{F4}")

  '適度なwait
  Sleep 3000
  
  Set Sh = Nothing

  'IEを閉じる
  IE.Quit
  Set IE = Nothing
  
  'IEのプロセスを強制終了
  'IEを閉じるだけではプロセスが残り,次回のNavigateで失敗する場合があるので念のため
  Shell "taskkill /f /im iexplore.exe"
  
  '適度なwait
  Sleep 3000
  
End Function


動けばいいやで作ったツールなので変なSleepの処理などはご容赦。