-
Notifications
You must be signed in to change notification settings - Fork 0
feat: サーバ・クライアントの実装 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Satorien
commented
Jan 1, 2026
- READMEに記載の仕様に基づいて実装
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a basic TCP socket-based server-client communication system in C. The server listens on port 8080 and handles arithmetic calculation requests via a /calc HTTP endpoint, while the client sends calculation queries and displays responses.
Key changes:
- Utility functions for socket initialization, error handling, and logging
- Server implementation with signal handling for graceful shutdown and request processing
- Client implementation with command-line argument support for sending calculation requests
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| utils.h | Declares utility functions for socket operations, error handling, and logging |
| utils.c | Implements utility functions for socket initialization, cleanup, error handling, and logging |
| server.c | Implements TCP server with HTTP-like request handling for arithmetic calculations |
| client.c | Implements TCP client that connects to server and sends calculation requests |
| Makefile | Build configuration for compiling server and client executables |
| .gitignore | Ignores compiled executables with run_* pattern |
Critical Issues Found:
- Multiple memory leaks in both server and client code
- Missing error checking on read/write operations
- Incorrect Content-Length in HTTP responses
- Security vulnerabilities including buffer overflow risks and unvalidated input
- Inappropriate error handling that terminates the server on malformed requests
- Signal handler with incorrect function signature
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 5 out of 6 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
変更は不要と判断したため、PRはクローズしました |
akmhmgc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
全体的に読みやすかったです!
不正な入力などの細かい対応は今後されると思うのでコメントはしていません。
| void connect_client_to_server(int client_socket_fd) { | ||
| // サーバアドレス構造体 | ||
| struct sockaddr_in server_address; | ||
| int domain = (strcmp(IP_VERSION, "IPv6") == 0) ? AF_INET6 : AF_INET; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
address familyなので変数名はdomainではなくaddress_family等が良いと思いました。
| while (sent_len < request_len) { | ||
| ssize_t n = write(client_socket_fd, request + sent_len, request_len - sent_len); | ||
| if (n < 0) { | ||
| handle_error("Write to server failed"); | ||
| } | ||
| sent_len += n; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
short count対策しているのが良いと思いました!
(nits) サーバー側でも同様の処理をしているのでラッパー関数を書いても良いかもしれません。
| void close_socket(int socket_fd) { | ||
| // ソケットのクローズ | ||
| if (close(socket_fd) < 0) { | ||
| handle_error("Close failed"); | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ソケットクローズ時のエラー対応しているの良いですね!
| size_t sent_len = 0; | ||
| while (sent_len < request_len) { | ||
| ssize_t n = write(client_socket_fd, request + sent_len, request_len - sent_len); | ||
| if (n < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EINTRはハンドラの処理が終わった後復帰する可能性があるのでリトライしても良いかもしれません。
| size_t request_len = strlen(request); | ||
| size_t sent_len = 0; | ||
| while (sent_len < request_len) { | ||
| ssize_t n = write(client_socket_fd, request + sent_len, request_len - sent_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
今だとサーバーのソケットが閉じている時にこのループでwriteが二回以上呼び出されると、SIGPIPEを受け取ってクライアントのプロセスが落ちると思います。
SIGPIPEを無視するにはwriteではなくてflagを利用できるsendを利用すると良いです。
ref: https://linuxjm.sourceforge.io/html/LDP_man-pages/man2/send.2.html
| void handle_client_request(int client_socket_fd) { | ||
| // リクエストの処理 | ||
| char *buffer = calloc(BUFFER_SIZE, 1); | ||
| ssize_t bytes_read = read(client_socket_fd, buffer, BUFFER_SIZE - 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writeと同様readもshort countの可能性があるのでループして要求した文字数分読めたかチェックした方が良さそうです。
| char *buffer = calloc(BUFFER_SIZE, 1); | ||
| ssize_t bytes_read = read(client_socket_fd, buffer, BUFFER_SIZE - 1); | ||
| if (bytes_read < 0) { | ||
| log_msg("Read from client failed\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ログを出して後続の処理に行ってしまうのでreturnした方が良いと思います。
| // アドレスの再利用を有効化 | ||
| int optval = 1; | ||
| if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { | ||
| log_msg("setsockopt SO_REUSEADDR failed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
エラーを見る限り致命的なものしかないので、ここで失敗した場合は処理を終了した方が良い気がします。
https://linuxjm.sourceforge.io/html/LDP_man-pages/man2/setsockopt.2.html
| } | ||
|
|
||
| // リクエストの受信と処理 | ||
| while (is_server_running) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
シグナルハンドラでフラグを変更してgraceful shutdownに対応しているは良いですね。参考になりました。
| size_t response_len = strlen(response); | ||
| size_t sent_len = 0; | ||
| while (sent_len < response_len) { | ||
| ssize_t n = write(client_socket_fd, response + sent_len, response_len - sent_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/Satorien/Socket-Programming/pull/1/changes#r2658611560
と同様にクライアントがソケットを閉じた後にwriteが呼び出されるとサーバーがクラッシュするのでsendでオプションを渡すのが良いと思います。