linuxCプログラミング実戦my_server.c例問題まとめ

8356 ワード

今日linux Cプログラミング実戦のmy_を見てサーバの例では、このコードをノックして、親子プロセスがsocketを閉じてclose呼び出しを行うことに疑問があります.
図に示す3つのclose socketのように、サブプロセス通信が終了して自分の通信を閉じることを考えるsocket:conn_fdは理解できるがsock_fd、サーバの傍受socketも閉鎖されたらどうしたのか分からない.また、親プロセスがclose(conn_fd)を実行してサブプロセスの通信socketをオフにすると、間もなくサブプロセスがクライアントsoketと通信できなくなりますか?しかし、プログラムは正常に動作しています.資料を再確認すると、サブプロセスリソースのコピーとclose関数、ファイル記述子の理解が不十分であることがわかりました.
 
1.まず、socketは特殊なデータ転送IOであり、ファイル記述子でもある.
2.forkプロセスを作成すると、サブプロセスは親プロセスが開いているファイル記述子を共有しますが、親プロセスのファイル記述子への変更は、サブプロセスのファイル記述子に影響しません.
3.close 1つのソケットのデフォルトの動作は、ソケットを閉じたとマークし、直ちに呼び出しプロセスに戻ることであり、このソケット記述子は呼び出しプロセスによって使用できない.すなわち、readまたはwriteの最初のパラメータとして使用できないが、TCPはキューに並んで送信を待っているデータを送信しようとする.送信が完了すると通常のTCP接続終了シーケンスが発生します.
マルチプロセス同時サーバでは、親子プロセスはソケットを共有し、ソケット記述子参照カウントは共有されたプロセス個数を記録し、親プロセスまたはあるサブプロセスcloseがソケットを削除すると、記述子参照カウントはそれに応じて1減少し、参照カウントがゼロより大きい場合、このclose呼び出しはTCPの4パス握手ブレークダウンプロセスを引き起こすことはありません.
 
したがって、親プロセスclose(conn_fd)は、サブプロセス通信に影響を与えません.逆に、そうしないと、親プロセスでconn_fdは使用可能なファイル記述子を占有し、conn_fdはユーザレベルの制限があり(カーネルはあるプロセスがすべてのファイルリソースを消費しないようにするために、単一プロセスの最大オープンファイル数に対してもデフォルト値処理を行い、デフォルト値は一般的に1024であり、ulimit-nコマンドを使用して表示できる)、新しい接続をacceptすると、前のconn_fdが上書きされ、見つからないが、対応する記述子値は「占有」は、ユーザーレベルの制限に達した場合、acceptの新しい接続はできず、ボトルネックとなります.
Webサーバでは、システムのデフォルト値ファイル記述子の最大値を変更することで、サーバを最適化するのが最も一般的な方法の1つです.最適化方法については、http://blog.csdn.net/kumu_linux/article/details/7877770を参照してください.
親プロセスのclose(conn_fd)を除去すると、acceptの接続数が大幅に減少すると本人が測定した.また、システムファイル記述子の最大値を変更することで、accept接続数を大幅に向上させることができます.
 
初学Linuxはその中の多くの細部に対してまだはっきりしていないで、後続は修正に対して!
ファイル記述子は良いブログを説明します.http://blog.csdn.net/cywosp/article/details/38965239
 
while(1) {

        conn_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &cli_len);

        if (conn_fd < 0) {

            my_err("accept", __LINE__);

        }

        printf("accept a new client, ip:%s
", inet_ntoa(cli_addr.sin_addr)); if ((pid = fork()) == 0) { while(1) { if ((ret = recv(conn_fd, recv_buf, sizeof(recv_buf), 0)) < 0) { perror("recv"); exit(1); } recv_buf[ret-1] = '\0'; if (flag_recv == USERNAME) { name_num = find_name(recv_buf); switch(name_num) { case -1: send_data(conn_fd, "n
"); break; case -2: exit(1); break; default: send_data(conn_fd, "y
"); flag_recv = PASSWORD; break; } } else if (flag_recv == PASSWORD) { if (strcmp(users[name_num].password, recv_buf) == 0) { send_data(conn_fd, "y
"); send_data(conn_fd, "welcome login my tcp server
"); printf("%s login
", users[name_num].username); flag_recv = MESSAGE; } else { send_data(conn_fd, "n
"); } } else if (flag_recv == MESSAGE) { if (strcmp("quit", recv_buf) == 0) { break; } printf("message from %s: %s
", users[name_num].username, recv_buf); } } close(sock_fd); close(conn_fd); printf("child exit!
"); exit(0); }else { close(conn_fd); }