-
Notifications
You must be signed in to change notification settings - Fork 0
クライアント・サーバーの実装課題 #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
hayashi-ay
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.
各システムコールと実際のTCP通信のフローがどう対応しているかなどは確認しておくと良いかなと思います。three way hand shakingはどれなど。必ずしもシステムコールと1対1で対応しているわけではないですが。
あとはrecv, send周りの処理は他の方のPRのコメントも参考にされると良いと思います。
あとは今のサーバーの実装はブロッキングになっている(1度に1つのクライアントとしか通信できない)と思うのでノンブロッキングにするとかですかね。selectシステムコールあたりを見てみると良いと思います。
client.c
Outdated
| #define BUFFER_SIZE (MESSAGE_SIZE + 1) | ||
|
|
||
| int main(int argc, char* argv[]) { | ||
| int sd; |
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.
あまり見ない命名な気がします。file descripterなのでfdとかですかね?
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.
socket descripterのつもりでした。
client.c
Outdated
| fprintf(stderr, "invalid IP address.\n"); | ||
| exit(EXIT_FAILURE); | ||
| } | ||
| if ((server_port = (unsigned short) atoi(argv[2])) == 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.
atoiよりかはstrotolの方がoverflowとかも分かるので良いかなと思います。あとはポート番号はもう少しバリデーションしても良いかなと思います。ex. wellknow portは使わせないなど https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
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.
参考資料もありがとうございます!
|
ご指摘いただいた点を意識して、もう少し色々調べてみます! |
inazz
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.
server/client 共通の話は片方にのみコメントしています。
IPv6に対応してみてください。
全てをメイン関数に書かず、適当な処理単位に分割し関数にして、名前を付けてください。
リモートからは任意のデータが飛んでくる可能性があると想定してください。最大長を仮定しないでください。
client.c
Outdated
| fprintf(stderr, "argument count missmatch.\n"); | ||
| exit(EXIT_FAILURE); | ||
| } | ||
| if (inet_aton(argv[1], &server_sa.sin_addr) == 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.
ip v6 や、ホスト名が指定されても通信できるようにしてほしい。
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.
以下で修正しました。
0b9dca6
client.c
Outdated
| } | ||
|
|
||
| memset(&server_sa, 0, sizeof(server_sa)); | ||
| server_sa.sin_family = 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.
これだと IPv4 のみになってしまうので、 v6 でも対応できるようにしたい。
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.
以下で修正しました。
0b9dca6
client.c
Outdated
| char receive_buffer[BUFFER_SIZE], send_buffer[BUFFER_SIZE]; | ||
|
|
||
| if (argc != 3) { | ||
| fprintf(stderr, "argument count missmatch.\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.
使う人にわかりやすいエラーメッセージを考えてみてください。
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.
以下で修正しました。
752536b
|
|
||
| while(1) { | ||
| printf("please enter the characters: "); | ||
| if (fgets(send_buffer, BUFFER_SIZE, stdin) == NULL) { |
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.
入力の終了に対応してください (EOF -- 一般的には、端末で Ctrl-D を押した場合)
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.
以下で修正しました。
fc9b5be
client.c
Outdated
| exit(EXIT_FAILURE); | ||
| } | ||
| // send | ||
| if (send(sd, send_buffer, strlen(send_buffer), 0) <= 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.
一部だけ送信に成功したケースを考慮してください。
client.c
Outdated
| int current_byte = 0; | ||
| while(current_byte < BUFFER_SIZE) { | ||
| // recv | ||
| received_byte = recv(sd, &receive_buffer[current_byte], 1, 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.
システムコールを呼び出すと、
CPU割込みが発生し、権限を切り替え、ユーザの権限やパラメータチェックをし、必要に応じてロックを取ったりと、、、と、データを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.
以下で修正しました。
fc9b5be
client.c
Outdated
| if (received_byte < 0) { | ||
| perror("recv() failed.\n"); | ||
| exit(EXIT_FAILURE); | ||
| } else if (received_byte == 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.
正常に最後までデータ後届いた場合もエラーになってしまっています。
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.
以下で修正しました。
fc9b5be
client.c
Outdated
|
|
||
| if (receive_buffer[current_byte] == '\n') { | ||
| receive_buffer[current_byte] = '\0'; | ||
| if (strcmp(receive_buffer, "quit") == 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.
receive_buffer に \0 が入っていない場合はバッファオーバーフローの危険性があります。
(実際には第2引数の5バイト目が\0なので起きないだろうとは推測しますが、strcmp は保証してくれない)
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.
以下で修正しました。(上記処理を廃止しました。)
fc9b5be
server.c
Outdated
|
|
||
| while(1) { | ||
| //recv | ||
| if ((receive_message_size = recv(client_sd, receive_buffer, BUFFER_SIZE, 0)) < 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.
recv も同様に一回で全部読めるとは保証されません。
また、先方から送られてくるデータがBUFFER_SIZEより多い場合はどうなるでしょう?
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.
送られてきたデータがバッファより大きい場合には、動的にバッファを拡大して対応できるように実装できそうです。(対応予定)
client.c
Outdated
| printf("received from server: %s\n", receive_buffer); | ||
| } | ||
| return EXIT_SUCCESS; | ||
| } 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.
一般的にテキストファイルの末尾は改行を入れることになっています。
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.
以下で修正しました。
ee4e10c
|
残課題メモ:
|
| @@ -0,0 +1,88 @@ | |||
| #include <stdio.h> | |||
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.
#include の順番に何か規則を持たせたい。 (<> -> "" の順番で、アルファベット順など)
| n = send(s, buf + sent_total, len - sent_total, 0); | ||
| if (n == -1) { | ||
| perror("send() failed.\n"); | ||
| exit(EXIT_FAILURE); |
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.
もし失敗時に exit するなら、 send_all_or_die みたいな名前にしたい。
| } | ||
| if (n == 0) { | ||
| printf("end of input detected (EOF).\n"); | ||
| return sent_total; |
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.
send_all なので、 paritial に終わらせたくない。
(partial な時に exit を呼ぶならエラー時と同じ挙動でまだ理解しやすいかも)
| return received_total; | ||
| } | ||
| received_total += n; | ||
| if (strchr(buf, '\n') != NULL) { |
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.
receive_all と書いてあるので、データの内容については触れたくない。
| printf("server disconnected.\n"); | ||
| break; | ||
| } | ||
| receive_buffer[receive_message_size] = '\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.
受け取ったデータがバッファ全部に詰まっていた際に、これはバッファの次のメモリ (out of bounds) になってしまう。
|
|
||
| while(1) { | ||
| //recv | ||
| receive_message_size = receive_all(client_sd, receive_buffer, BUFFER_SIZE); |
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.
receive_all はエラー時に exit するけれど、
client の一つが通信エラー発生しただけでサーバーを終了させたくない。
一旦動作確認が出来たのでPRを出します。
他の方々のPRのコメントを確認しましたが、
などに課題を感じました。
C言語に慣れておらず、都度キャッチアップしながら書いているので、おかしなところが多々あるかもしれません。
お作法等も併せてコメント頂けるとありがたいです。