From 74df32664728e8ab8ec9b36269136bab86e660b7 Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Mon, 25 May 2026 02:06:39 +0900 Subject: [PATCH 1/4] =?UTF-8?q?HTTP=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=82=92=E4=BD=9C=E3=81=A3=E3=81=A6=E3=81=BF=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes socket_programming/.DS_Store | Bin 0 -> 6148 bytes socket_programming/README.md | 53 +++++++++ socket_programming/client | Bin 0 -> 34232 bytes socket_programming/client.c | 49 ++++++++ socket_programming/server | Bin 0 -> 34840 bytes socket_programming/server.c | 214 +++++++++++++++++++++++++++++++++++ 7 files changed, 316 insertions(+) create mode 100644 .DS_Store create mode 100644 socket_programming/.DS_Store create mode 100644 socket_programming/README.md create mode 100755 socket_programming/client create mode 100644 socket_programming/client.c create mode 100755 socket_programming/server create mode 100644 socket_programming/server.c diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..45d322a9022b588216f5b1a282aa174514288b3f GIT binary patch literal 6148 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 literal 0 HcmV?d00001 diff --git a/socket_programming/client.c b/socket_programming/client.c new file mode 100644 index 0000000..db053de --- /dev/null +++ b/socket_programming/client.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include + +#define HOST "127.0.0.1" +#define PORT "8080" + +int main(int argc, char *argv[]) { + const char *expr = (argc > 1) ? argv[1] : "2+10"; + + struct addrinfo hints, *res; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + int rv = getaddrinfo(HOST, PORT, &hints, &res); + if (rv != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } + + int sfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sfd < 0) { perror("socket"); return 1; } + + if (connect(sfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); return 1; } + freeaddrinfo(res); + + /* リクエスト送信 */ + char req[512]; + int reqlen = snprintf(req, sizeof req, + "GET /calc?query=%s HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n", + expr); + write(sfd, req, reqlen); + + /* レスポンス受信・表示 */ + char buf[4096]; + ssize_t n; + while ((n = read(sfd, buf, sizeof buf - 1)) > 0) { + buf[n] = '\0'; + printf("%s", buf); + } + printf("\n"); + close(sfd); + return 0; +} diff --git a/socket_programming/server b/socket_programming/server new file mode 100755 index 0000000000000000000000000000000000000000..5e7c4ebcf6dbf8921170f54ae552cd8de78037d2 GIT binary patch literal 34840 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 literal 0 HcmV?d00001 diff --git a/socket_programming/server.c b/socket_programming/server.c new file mode 100644 index 0000000..cb931f0 --- /dev/null +++ b/socket_programming/server.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT "8080" +#define BACKLOG 10 +#define BUF_SIZE 4096 + +/* ------------------------------------------------------- + * /calc?query= を評価する + * 対応演算子: + - * / + * 返り値: 動的確保した結果文字列(呼び出し元が free する) + * エラー時は NULL + * ------------------------------------------------------- */ +static char *calc(const char *query_string) { + /* query_string は "query=2+10" など */ + const char *eq = strchr(query_string, '='); + if (!eq) return NULL; + + const char *expr = eq + 1; // const char* + printf("DEBUG expr: [%s]\n", expr); + + double left, right; + char op; + if (sscanf(expr, " %lf %c %lf", &left, &op, &right) != 3) { + return NULL; // free(expr) を削除 + } + + double result; + switch (op) { + case '+': result = left + right; break; + case '-': result = left - right; break; + case '*': result = left * right; break; + case '/': + if (right == 0) return NULL; + result = left / right; + break; + default: return NULL; + } + + /* 整数なら整数表示、そうでなければ小数表示 */ + char *buf = malloc(64); + if (!buf) { perror("malloc"); exit(1); } + if (result == (long long)result) + snprintf(buf, 64, "%lld", (long long)result); + else + snprintf(buf, 64, "%g", result); + return buf; +} + +/* ------------------------------------------------------- + * 1リクエストの処理 + * ------------------------------------------------------- */ +static void handle_request(int fd) { + /* リクエスト全体を読む */ + char *req = malloc(BUF_SIZE); + if (!req) { perror("malloc"); exit(1); } + ssize_t total = 0; + while (total < BUF_SIZE - 1) { + ssize_t n = read(fd, req + total, BUF_SIZE - 1 - total); + if (n < 0) { perror("read"); free(req); return; } + if (n == 0) break; + total += n; + /* ヘッダー終端 \r\n\r\n が来たら終了 */ + req[total] = '\0'; + if (strstr(req, "\r\n\r\n")) break; + } + req[total] = '\0'; + printf("--- request ---\n%s\n", req); + + /* リクエストライン解析: "GET /path?query HTTP/1.x" */ + char method[16], path[1024], version[16]; + if (sscanf(req, "%15s %1023s %15s", method, path, version) != 3) { + free(req); + return; + } + free(req); + + /* パスとクエリ文字列に分割 */ + char *qmark = strchr(path, '?'); + char *query_string = NULL; + if (qmark) { + *qmark = '\0'; + query_string = qmark + 1; + } + + /* レスポンスボディ生成 */ + char *body = NULL; + int status = 200; + const char *status_msg = "OK"; + + if (strcmp(method, "GET") == 0 && strcmp(path, "/calc") == 0 && query_string) { + body = calc(query_string); + } + + if (!body) { + status = 400; + status_msg = "Bad Request"; + body = strdup("Bad Request"); + if (!body) { perror("strdup"); exit(1); } + } + + /* レスポンス送信 */ + size_t body_len = strlen(body); + char *header = malloc(256); + if (!header) { perror("malloc"); exit(1); } + int hlen = snprintf(header, 256, + "HTTP/1.1 %d %s\r\n" + "Content-Length: %zu\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n" + "\r\n", + status, status_msg, body_len); + + /* ヘッダー */ + ssize_t written = 0; + while (written < hlen) { + ssize_t n = write(fd, header + written, hlen - written); + if (n < 0) { perror("write"); break; } + written += n; + } + /* ボディ */ + written = 0; + while ((size_t)written < body_len) { + ssize_t n = write(fd, body + written, body_len - written); + if (n < 0) { perror("write"); break; } + written += n; + } + + free(header); + free(body); +} + +/* ------------------------------------------------------- + * サーバーソケット作成 (IPv4/IPv6 両対応) + * ------------------------------------------------------- */ +static int create_server_socket(void) { + struct addrinfo hints, *res, *p; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; /* IPv4 / IPv6 どちらでも */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; /* INADDR_ANY */ + + int rv = getaddrinfo(NULL, PORT, &hints, &res); + if (rv != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + exit(1); + } + + int sfd = -1; + for (p = res; p != NULL; p = p->ai_next) { + sfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if (sfd < 0) { perror("socket"); continue; } + + int yes = 1; + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { + perror("setsockopt"); close(sfd); continue; + } + + if (bind(sfd, p->ai_addr, p->ai_addrlen) < 0) { + perror("bind"); close(sfd); continue; + } + break; /* 成功 */ + } + freeaddrinfo(res); + + if (sfd < 0) { + fprintf(stderr, "failed to bind\n"); + exit(1); + } + + if (listen(sfd, BACKLOG) < 0) { + perror("listen"); exit(1); + } + return sfd; +} + +/* ------------------------------------------------------- + * main + * ------------------------------------------------------- */ +int main(void) { + int sfd = create_server_socket(); + printf("Listening on port %s ...\n", PORT); + + while (1) { + struct sockaddr_storage client_addr; + socklen_t addrlen = sizeof client_addr; + int cfd = accept(sfd, (struct sockaddr *)&client_addr, &addrlen); + if (cfd < 0) { perror("accept"); continue; } + + /* クライアントの IP アドレスを表示 */ + char ipstr[INET6_ADDRSTRLEN]; + if (client_addr.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&client_addr; + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); + } else { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)&client_addr; + inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); + } + printf("Connection from %s\n", ipstr); + + handle_request(cfd); + close(cfd); + } + + close(sfd); + return 0; +} From 4651a6c07d25ee010f4771ffc77467229647dc87 Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Fri, 29 May 2026 01:00:57 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E6=82=AA=E6=84=8F=E3=81=82=E3=82=8B?= =?UTF-8?q?=E8=80=85=E3=81=8C=E3=83=A1=E3=83=A2=E3=83=AA=E3=83=80=E3=83=B3?= =?UTF-8?q?=E3=83=97=E3=81=8B=E3=82=89=E3=83=9D=E3=82=A4=E3=83=B3=E3=82=BF?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E5=80=A4=E3=82=92=E8=AA=AD=E3=81=BF=E3=80=81?= =?UTF-8?q?=E8=A7=A3=E6=94=BE=E9=9A=85=E3=81=AE=E3=83=A1=E3=83=A2=E3=83=AA?= =?UTF-8?q?=E9=A0=98=E5=9F=9F=E3=81=AB=E6=AE=8B=E3=81=A3=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=82=8B=E4=BE=A1=E5=80=A4=E3=81=82=E3=82=8B=E3=83=87=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=82=92=E7=9B=97=E3=82=81=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- socket_programming/server.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/socket_programming/server.c b/socket_programming/server.c index cb931f0..4f7d0ee 100644 --- a/socket_programming/server.c +++ b/socket_programming/server.c @@ -64,7 +64,7 @@ static void handle_request(int fd) { ssize_t total = 0; while (total < BUF_SIZE - 1) { ssize_t n = read(fd, req + total, BUF_SIZE - 1 - total); - if (n < 0) { perror("read"); free(req); return; } + if (n < 0) { perror("read"); free(req); req = NULL; return; } if (n == 0) break; total += n; /* ヘッダー終端 \r\n\r\n が来たら終了 */ @@ -78,9 +78,11 @@ static void handle_request(int fd) { char method[16], path[1024], version[16]; if (sscanf(req, "%15s %1023s %15s", method, path, version) != 3) { free(req); + req = NULL; return; } free(req); + req = NULL; /* パスとクエリ文字列に分割 */ char *qmark = strchr(path, '?'); @@ -134,7 +136,9 @@ static void handle_request(int fd) { } free(header); + header = NULL; free(body); + body = NULL; } /* ------------------------------------------------------- From 911960b1367b203256a192c9fd456fddaee8fb4f Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Sat, 30 May 2026 13:07:07 +0900 Subject: [PATCH 3/4] =?UTF-8?q?clinet=20=E3=81=AE=E5=87=A6=E7=90=86?= =?UTF-8?q?=E3=82=92=E4=B8=80=E8=A1=8C=E3=81=9A=E3=81=A4=E6=B7=B1=E3=82=81?= =?UTF-8?q?=E3=81=AB=E8=BF=BD=E3=81=A3=E3=81=A6=E3=81=84=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- socket_programming/addrinfo_test | Bin 0 -> 33760 bytes socket_programming/addrinfo_test.c | 33 +++++++++++++++++++++++ socket_programming/client.c | 42 ++++++++++++++++++++++++++--- socket_programming/server | Bin 34840 -> 34888 bytes 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100755 socket_programming/addrinfo_test create mode 100644 socket_programming/addrinfo_test.c diff --git a/socket_programming/addrinfo_test b/socket_programming/addrinfo_test new file mode 100755 index 0000000000000000000000000000000000000000..2bc232e28c31acfb310afe78b78d149472598c4b GIT binary patch literal 33760 zcmeI5e{54#6vxkNx7m%sI)2SLbR`N*K(;8F#Ta~J%&`b;!qn+lE@SPsX59*HhrzS=X{E)lgMi^J>k;dWois zadUd;4o~t7@<62;YnmF29kYrOU*?sP zEQ+RVHk1lSdbfsCq0D?)Ic7d#AR@j!pUcX}3=L7LEgT8?dpc5n`h3?}`JS=*#kY$+ zx5Sm|?Rm}L<5m8i_MqXX=Nq*0HCai-&&*+U8I7#NAy%ciP|v%+=7XO~9=o z8Lg9pqJq`Us#HhNwhVX8SIJ`y(arlUk7U~RsZZ~-b#)t_uUS)<+#}J9y4V+)kYZS* z9&4!$eXTJI&&?B-f1dpc_Jz&;tn?O9E;r}7?c;U^YXhrYWUT0Y_F#rR#P`q4 zh>1Ik)x#?LqP#a8Di8R#mV0*wyzGmVuu2^z&mLXfT=e7%BU6PpJ}CCQ{5Z!vtQsp( z0dM{S!#1Xyy+3OyM~(Rz{X}IvKgqL&_qko${1Lm_?9KYQ^^Th3HXN+qda%JlY zm!>C%2TE^h6y5k`^@7tA16pjNgc6RN=(m2NgI7!R#8d~3mT`Z)i$*#55LFb%_;EuE zn~GyUwrR0fc-&MyjmFFMM0^<~xNmNJ8QVE@DrxhxMqRnI{j7r;Q?WuG^DwdM39XP~ zIzQv+Wg5R)M2WAmqZ^;&yzwGEFCc+yF+r5Yv5vMFKI5h#vT^O$+o^IVdz zl=GExzJ(MUb6WZ4nE7};560*GMZV$USUHa|>f>j+vZ*l6^Gek_kMr~VE=)}o#kpVV zDdT#KT7D{ydHCK5W-y!E;p)w&xt7rr1L~%owM)zWWeb@McoQ6)DAh-A_pd*}Ys2-b zOBKx3?a&kCC^hXon?1{B&$ij~ZT17E9SF9y20DY`2vt^8R#5XIZ;Pj{VaLj+J&VG5 zDfcPUy*4x$A0A}edo8*z&)DM&cv2$vR`#y!ZJk?D`TrHsjqCJ9ejoXq#cgCV;u*h) z>9Mdt00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;K;ZvRz#ZlHOlCr!B6Qr(@(*XL{Njrde2r}Tv=x4YHfBL}w2faLH3 z&288+@A<3+Y{;3@;>%go+=^+)3clL?stmtA!{40YcVzg%3}3##Ak5`^3-YZ6Sq~{y z;_^*~KkMT#c^KuL(^bZF|4Zz*e#jqVB8RzzB%`?;lU?u*Ik;MfQ93UWHL;5167AMK z4nD5?ABlF%8m1-pfr|L}jPWxM{T7QYznC{;ZqDBNz^bMD4<9++e7)uE-9a~f3a`v-sK +#include +#include +#include +#include +#include + +int main() { + struct addrinfo hints, *res, *p; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + getaddrinfo("localhost", "8080", &hints, &res); + + int count = 0; + for (p = res; p != NULL; p = p->ai_next) { + char ipstr[INET6_ADDRSTRLEN]; + if (p->ai_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)p->ai_addr; + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); + printf("[%d] IPv4: %s\n", count, ipstr); + } else { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)p->ai_addr; + inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); + printf("[%d] IPv6: %s\n", count, ipstr); + } + count++; + } + printf("合計: %d個\n", count); + freeaddrinfo(res); +} \ No newline at end of file diff --git a/socket_programming/client.c b/socket_programming/client.c index db053de..ec4ca82 100644 --- a/socket_programming/client.c +++ b/socket_programming/client.c @@ -12,18 +12,52 @@ int main(int argc, char *argv[]) { const char *expr = (argc > 1) ? argv[1] : "2+10"; - struct addrinfo hints, *res; + struct addrinfo hints + struct addrinfo *res; + + // hints = addrinfo の実体(箱そのもの) + // &hints = hints の住所 + // res = 住所を入れる変数(まだ空) + // getaddrinfo = res に住所を入れてくれる + memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; + // hints を全て0埋めしてくれる + // addrinfo の構造体は以下 + // struct addrinfo { + // int ai_flags; /* input flags */ + // int ai_family; /* protocol family for socket */ --> AF-INET(IPv4) or AF_INET6(IPv6) + // int ai_socktype; /* socket type */ --> TCP or UDP + // int ai_protocol; /* protocol for socket */ --> IPPROTO_TCP or IPPROTO_UDP + // socklen_t ai_addrlen; /* length of socket-address */ --> ai_addr のサイズ + // struct sockaddr *ai_addr; /* socket-address for socket */ --> 実際のアドレス+ポート番号 + // char *ai_canonname; /* canonical name for service location */ --> ホスト名 + // struct addrinfo *ai_next; /* pointer to next in list */ --> 次の addrinfo ノードへのポインタ + // }; + // *ai_next が LinkedList みたいにポインタで次の要素を指してくれるので、server.c 側で for (p = res; p != NULL; p->ai_next)とかけた + // なぜLinkedListのような構造なのか? + // 1つのホストに対して、複数アドレスが返ってくる可能性があるため + // 検証コードを addrinfo_text.c において、実行結果を見ると + // ➜ socket_programming git:(socket-programming) ✗ gcc -o addrinfo_test addrinfo_test.c && ./addrinfo_test + // [0] IPv6: ::1 + // [1] IPv4: 127.0.0.1 + // 合計: 2個 + // IPv4, IPv6 の2つのアドレスが返ってくる、server.c では、この2つのアドレスに対して bind を試みる + + hints.ai_family = AF_UNSPEC; // IPv4, IPv6 どちらも対応 hints.ai_socktype = SOCK_STREAM; + // man 2 socket で確認。 + // TCP のこと、順序保証、信頼性、双方向接続 + // A SOCK_STREAM type provides sequenced, reliable, two-way connection based byte streams. + // SOCK_DGRAM: UDP, connectionless, unreliable message + // SOCK_RAW: 内部ネットワークプロトコルへの直接アクセス、root権限が必要 int rv = getaddrinfo(HOST, PORT, &hints, &res); if (rv != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } int sfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sfd < 0) { perror("socket"); return 1; } + if (sfd < 0) { perror("socket"); freeaddrinfo(res); return 1; } - if (connect(sfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); return 1; } + if (connect(sfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); close(sfd); return 1; } freeaddrinfo(res); /* リクエスト送信 */ diff --git a/socket_programming/server b/socket_programming/server index 5e7c4ebcf6dbf8921170f54ae552cd8de78037d2..3a84cbc0fcd09afae12f3b0447d6b10fed1a8ab4 100755 GIT binary patch delta 1497 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 Ix+C7$zmj=%mH+?% From 1ce10297c7ffff54d280575990b25e2c8ca1f57d Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Sat, 30 May 2026 23:28:31 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=E3=83=A1=E3=83=A2=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ・曖昧な理解だったDNSの話 ・クライアント側の処理の流れ --- socket_programming/addrinfo_test | Bin 33760 -> 33760 bytes socket_programming/addrinfo_test.c | 3 ++- socket_programming/client.c | 35 ++++++++++++++++++++--------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/socket_programming/addrinfo_test b/socket_programming/addrinfo_test index 2bc232e28c31acfb310afe78b78d149472598c4b..ee6759ad57c7a7157d74b85a1ac786d68547440a 100755 GIT binary patch delta 460 zcmaFR&h((2X~GT0I}>lZ3)-+TFfcMOFn9nl2-r+EWV9D-fr=)8#TXb`CN}~_pFl+; zprTJUUu0a*C@{DE0Lz74)=O45S^eH6x9ZvC3Cut1#TkAwu{B&OXJDA}Kb>Kx217&8 zi)@CSFOnH2zK~}4`9j~}=SyaWi5iRyKY^xAU=Wa+m=9F@NZjG)V`&G7ScKF>pwlKO zHb_m32g+gSnIbhY31q%M&|IK-FSHqc0@aJW(02Ga`2ve2hcLs>!>kQKZj%#P6`1Zw zO*Up#)8dDS8G+2>2fD%EVdpDm&Q&0{XaU`#!3uScg!JTQRx8mE>4^$Jr4N9{3jygB z&M`Y)h)=%6s>~=p`5SAPQBrDJeo?BGLQ!h5f~|sT0T)9~esW??Mt*S#gN1>G0YhS1 zNotXm0z$#$D7G+0o6Q^9ep+m1bC~O7eg_(wjEN~JMVWbN`SB&GK;4gX4?7C9eA~Ks hwZ{|HFRP3_oI2!d^v}-7VZGQoLCAZ~=37l{i~zk9m-YYv delta 327 zcmaFR&h((2X~GT0B@=JD3$m~=FfcMOFn9nl2(U~xWV9Fbfr{Ed1Q~oLHv&aFprR2_ z(T>d*8P_ukNZT)RiWWBwT=QS>?KDY+@W~UHe;P1jPu+iI0;RCq_>G$P&OS&hYavYeSG5P}2+X$$qTTOgWO1 zvsu+Rgdq|}lRa4#m{v$m-py(y`b2V~0#M-teTSbyKzfC9%#IiGleyTG8RaMIv4!#F zTQWaJl@FjyE^7);*A7RJc3nV0>i#pD3?n9XbsbDhkWKs~~kn37VInU|IyUy=$` szfbP-#ECkWxwu8xI{kC(wEAZ)SQh;(wq;py_2pypE21~wYGPvq03woNy#N3J diff --git a/socket_programming/addrinfo_test.c b/socket_programming/addrinfo_test.c index 17c6ae5..0e1992a 100644 --- a/socket_programming/addrinfo_test.c +++ b/socket_programming/addrinfo_test.c @@ -1,4 +1,3 @@ -// 確認用コード #include #include #include @@ -12,7 +11,9 @@ int main() { hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + printf("before: res = %p\n", (void *)res); getaddrinfo("localhost", "8080", &hints, &res); + printf("after: res = %p\n", (void *)res); int count = 0; for (p = res; p != NULL; p = p->ai_next) { diff --git a/socket_programming/client.c b/socket_programming/client.c index ec4ca82..73c39d5 100644 --- a/socket_programming/client.c +++ b/socket_programming/client.c @@ -6,20 +6,29 @@ #include #include +// サーバーのIPアドレスとPORT番号 +// ドメイン名(例: google.com)が指定された場合: +// 1. まず ISP(ソフトバンク、NTTなど)の DNS サーバーに問い合わせる +// 2. ISP が知らなければルート DNS サーバー(世界13台)に問い合わせる +// 3. さらに権威 DNS サーバーに問い合わせて IP アドレスを取得 +// 4. 返ってきた IP アドレスの HOST:PORT に connect() しに行く +// ※ DNSはサーバーのポートは返さないが、PORTは http: 80, https: 443 なので特別指定しなくても問題ない + +// 自分のPCが契約しているプロバイダのDNSをちゃんと使っているのか調べてみた +// ➜ / cat etc/resolv.conf : 自分のルーターが使っているIPアドレスがわかる +// ➜ / scutil --dns: +// → / nslookup xxxx:xxxx:xx:xxx....:xxx +// → / whois xxxx:xxxx:xx:xxx....:xxx: descr: BBIX IPv6 Network SoftbankBB ABUSE e-mail: abuse@e.softbank.co.jp +// うん、ちゃんと使ってた #define HOST "127.0.0.1" #define PORT "8080" int main(int argc, char *argv[]) { const char *expr = (argc > 1) ? argv[1] : "2+10"; - struct addrinfo hints + struct addrinfo hints; struct addrinfo *res; - // hints = addrinfo の実体(箱そのもの) - // &hints = hints の住所 - // res = 住所を入れる変数(まだ空) - // getaddrinfo = res に住所を入れてくれる - memset(&hints, 0, sizeof hints); // hints を全て0埋めしてくれる // addrinfo の構造体は以下 @@ -51,17 +60,23 @@ int main(int argc, char *argv[]) { // SOCK_DGRAM: UDP, connectionless, unreliable message // SOCK_RAW: 内部ネットワークプロトコルへの直接アクセス、root権限が必要 - int rv = getaddrinfo(HOST, PORT, &hints, &res); + int rv = getaddrinfo(HOST, PORT, &hints, &res); // HOST: 接続先のIPアドレス, PORT: 接続先のポート if (rv != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } int sfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + // アロー演算子、ポインタ経由でアクセスしている + // Java で書くところの res.ai_family と同じ + // man 2 socket + // RETURN VALUES + // A -1 is returned if an error occurs, otherwise the return value is a descriptor referencing the socket. + if (sfd < 0) { perror("socket"); freeaddrinfo(res); return 1; } - if (connect(sfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); close(sfd); return 1; } + if (connect(sfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect"); close(sfd); freeaddrinfo(res); return 1; } freeaddrinfo(res); /* リクエスト送信 */ - char req[512]; + char req[512]; // スタック領域に512byte確保 int reqlen = snprintf(req, sizeof req, "GET /calc?query=%s HTTP/1.1\r\n" "Host: localhost\r\n" @@ -71,7 +86,7 @@ int main(int argc, char *argv[]) { write(sfd, req, reqlen); /* レスポンス受信・表示 */ - char buf[4096]; + char buf[4096]; // スタック領域に4096byte確保、スタックはメモリ領域の名前で、取り出されると自動でその分のメモリは解放される特徴がある。free()不要 ssize_t n; while ((n = read(sfd, buf, sizeof buf - 1)) > 0) { buf[n] = '\0';