Outlookに他人の予定表を表示させる方法を追加
https://www.codeproject.com/articles/13071/programming-windows-tcp-sockets-in-c-for-the-begin
Byte Order
htonl()
--------------------------------------------------------------
Winsock (Windows Sockets API)
http://wisdom.sakura.ne.jp/system/winapi/winsock/
http://www.geekpage.jp/programming/winsock/
http://eternalwindows.jp/network/winsock/winsock05c.html
* 準備
以下のヘッダをインクルード
#include <winsock.h>
以下のライブラリをリンク
ws2_32.lib
* 初期化
Winsockを使うには以下を最初に行っておく
---
int main() {
WSADATA wDat;
WSAStartup(MAKEWORD(2,0),&wDat); // 初期化
// socket を使った処理
WSACleanup(); // 終了
}
---
WSACleanup();
を2回書いたら Cntrl-C で終わらずゾンビ化した
WSAGetLastError() は後述
* ソケット作成(server)
---
// Winsock 初期化
SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // ソケット作成
struct sockaddr_in addr; // アドレス構造体 下記参照
// addr に port, IP address など設定
bind( s, (struct sockaddr *)&addr, sizeof(addr)) // name づけ
listen(s, 5) // allocate queue 最大5個まで要求をqueueに入れる
SOCKET client_s;
struct sockaddr_in addr_client; int len= sizeof(addr_client);
while (1) { // each session from client
client_s = accept(s, (struct sockaddr *)&addr_client, &len); // wait
// client と通信
closesocket(client_s); // client 閉じる
}
shutdown(s, SD_BOTH); // 相手に切断通知
closesocket(s); // server socket 閉じる
// Winsock 終了
---
http://software.aufheben.info/kouza/senior/kouza_socket3.html
server socket の option
BOOL yes = 1;
setsockopt(sock0, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes));
// bind の前に使う。TIME_WAIT 状態のポートでも bind できるようになる。
int setsockopt(
_In_ SOCKET s,
_In_ int level,
_In_ int optname,
_In_ const char *optval,
_In_ int optlen
);
level = SOL_SOCKET
- SO_RCVTIMEO, DWORD blocking recv に timeout を msec で設定
- SO_SNDTIMEO, DWORD blocking send に timeout を msec で設定
* ソケット作成(client)
---
// Winsock 初期化
// getaddrinfo による接続相手の確認。失敗すればエラー終了
SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // ソケット作成
struct sockaddr_in addr; // アドレス構造体 下記参照
// addr に server の port, IP address など設定
connect( s, (struct sockaddr *)&addr, sizeof(addr)) // サーバと接続
// server と通信
shutdown(s, SD_BOTH); // 相手に切断通知
closesocket(s); // socket 閉じる
// Winsock 終了
---
// getaddrinfo による接続相手の確認。失敗すればエラー終了
if ( getaddrinfo("localhost", "3000", &addrHints, &lpAddrList) != 0) {
"3000" : port number (string!!)
* 受信
int recv (
IN SOCKET s,
OUT char FAR* buf,
IN int len,
IN int flag // 0: no option
);
if succeeded, return the num of bytes received
ネットワークが通常に切断された場合は 0
otherwise SOCKET_ERROR
エラー要因は WSAGetLastError() で調査
WSAENOTCONN 接続していない
WSAETIMEDOUT タイムアウト
* 送信
int send (
IN SOCKET s,
IN char FAR* buf,
IN int len, // byte
IN int flag
);
if succeeded, return the num of bytes sent, otherwise SOCKET_ERROR
エラー要因は WSAGetLastError() で調査
WSAENOTCONN 接続していない
WSAETIMEDOUT タイムアウト
* アドレス構造体
struct sockaddr_in
struct sockaddr_in6 // IPv6?
=> struct sockaddr にキャスト可
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
* int WSAGetLastError()
失敗した最後の Winsock 関数のエラーを返す
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms737828(v=vs.85).aspx
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms740668(v=vs.85).aspx
WSAEWOULDBLOCK
noblocking がすぐに終わらない。たとえば recv が受信できないなど。
WSAETIMEDOUT 10060
connection timeout
* byte order
u_long htonl (u_long hostlong); // host -> network
u_short htons (u_short hostshort);
u_long ntohl (u_long netlong); // network -> host
u_short ntohs (u_short netshort);
* blocking mode
recv は default で blocking (動作終了まで制御を返さない)
non-blocking に切り替えるには ioctlsocket() を使う
int ioctlsocket(
SOCKET s,
long cmd, // socket に設定したいコマンドの種類
u_long *argp
);
non-blocking にするには
cmd = FIONBIO, *argp != 0
non-blocking にすることで、ブロックされずフラグをチェックできる
=> どこかで sleep する必要あり
これの代わりに WSAWaitForMultipleEvents() を使ってもよい
* WSAWaitForMultipleEvents
hEvent = WSACreateEvent();
WSAEventSelect(soc, hEvent, FD_READ | FD_CLOSE); // hEvent は read or close
hEvntArray[0] = hEvent; // 上の socket の event
hEvntArray[1] = g_hEventExit; // 他のコードで発生した event
--------------------------------------------------------------
* timeout と select
fd_set fds, readfds;
struct timeval tv;
sock1 = socket(,,); sock2 = socket(,,);
bind(sock1, &addr1, ); bind(sock2, &addr2, );
FD_ZERO(&readfds); // initialization
FD_SET(sock1, &readfds); FD_SET(sock2, &readfds); // entry sockets as read socket for selecct
tv.tv_sec = 10; tv.tv_usec = 0; // timeout 10 sec.
while (1) {
memcpy(&fds, &readfds, sizeof(fd_set)); // initialize fds by readfds
n = select(0, &fds, NULL, NULL, &tv);
if (FD_ISSET(sock1, &fds) ) { // sock1に読み込み可能なデータがある recv(sock1)... }
if ( n == 0 ) { // select returns 0 when timeout
break;
}
recv(sock1); ...
}
int select(
_In_ int nfds, // set always 0
_Inout_ fd_set *readfds,
_Inout_ fd_set *writefds,
_Inout_ fd_set *exceptfds,
_In_ const struct timeval *timeout
);
setsockopt
https://msdn.microsoft.com/en-us/library/ms740532(v=vs.85).aspx
timeout SO_RCVTIMEO SO_SNDTIMEO
SO_KEEPALIVE
buffer space SO_RCVBUF
--------------------------------------------------------------
Windows API
http://www.wisdomsoft.jp/421.html
http://keicode.com/winprimer/wp07.php
WINAPI は __stdcall #define WINAPI __stdcall (in WinDef.h)