ソケットプログラミング(UDP)
この手の例は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
実行結果
画面ログに残すだけなら下記。
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で某コンビニの入店音ぽい音
WindowsのPowerShellでbeep音を出す。
折角なのであのメロディーの再現にトライしてみた。
実行に必要な準備
- PowerShellのインストール
- Windowsメニュー → アクセサリ → PowerShellを右クリック → 管理として起動
- PowerShellスクリプトの実行セキュリティポリシーを変更
実行するスクリプト(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>
実行結果
今のところ4分音符の使い方しかわからず。
途中に2分音符や8分音符を挟むにはどうすればよいのだろう。
X11で始めるGUIプログラミング
いまどきX11でプログラム書くことがあるかは知らないけど、
凄い昔にLinuxでGUIのプログラミングにトライしたときのサンプルコードを見つけたので掲載。
現代は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
URLを指定して開いたページをPDFで保存する
IEで特定のページを開く→ 仮想プリンタでPDF印刷という作業を繰り返したい人向け。
[作業の流れ]
- 仮想プリンタ(BullzipやPDF reDirect等)をインストールして通常使うプリンタに設定する。
- ExcelでURLのリストを作り、マクロにPDF化するプログラムを記載して実行。
PDF_PRINT.xlsm
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の処理などはご容赦。