fork()理解と簡単な同時サーバ応用

2638 ワード

まず、混同しやすいところが2つあると思います.
1,fork()関数は、新しいプロセスを作成するのではなく、現在のプロセスをコピーします.
2,fork()関数は共有実行され,2種類の戻り値がある.
================================================
最初の点:
親プロセスfork()の後、サブプロセスは完全に親プロセスと等しくなり、データ・セグメントとコード・セグメントが含まれます.データセグメントは2つ同じであり、コードセグメントは1つしか共有されていないことが理解される.分子プロセスと親プロセスをどのように区別するかについては、2つ目のポイントで説明します.
特に「レプリケーション」という概念を強調するもう一つの理由はfork()が新しいプロセスを作成するために使用されていないためであり、一般的にLinuxの下にはsystem()とexec()の2つの新しいプロセスを作成する方法がある.
System()の最下位はexec()で、shellを再起動して新しいプロセスを実行します.exec()は、現在のプロセスを新しいプロセスに置き換えます.
exec()で新しいプロセスを作成する場合は、fork()と協力してプロセスをコピーし、exec()を呼び出してレプリカを置き換える必要があります.、
補足:Linuxの下のプロセスはとても安くて、マルチプロセスはいつもマルチスレッドよりもっと便利で、彼らの異同について、最も主要なのはマルチスレッドの中で、データセグメントは共有して、マルチプロセスの中で、上述のように、独立性はとても高いです.
2番目のポイント:
サブプロセスと親プロセスコードセグメントは共有されているため、これはマルチスレッドと同じであり、サブプロセスを作成するとすぐに同じ関数が実行され、自然にサブプロセスもfork()関数が実行されますが、新しいプロセスは作成されず、戻り値が親プロセスとは異なります.これが分子プロセスと親プロセスを区別する方法です.
================================================
1つの例:単純なマルチプロセス同時サーバフレームワーク:
pid_t pid;
int listenfd, connfd;

listenfd = Socket( ... );

/* fill in sockaddr_in{} with server's well-known port */
Bind(listenfd, ... );
Listen(listenfd, LISTENQ);

for ( ; ; ) {
connfd = Accept (listenfd, ... ); /* probably blocks */

if ( (pid = fork()) == 0) {
#2 Close(listenfd); /* child closes listening socket */
doit(connfd); /* process the request */
Close(connfd); /* done with this client */
exit(0); /* child terminates */
}

#1 Close(connfd); /* parent closes connected socket */
}

以上はフレームワークにすぎず、多くのコードが簡略化されており、fork()の一般的な使用方法:if((pid=fork()==0)のコードブロックがサブプロセスで実行できる領域であることがわかります.さらに、listenfdとconnfdはcloseに2回使用されるため、システムのソケットの使用はカウントされ、カウントが0のときに本当に閉じる必要があることに特に注意してください.また、親プロセスはlistenfdのみに関心を持っているため、親プロセス領域ではconnfd(#1)を閉じる必要があります.サブプロセスはconnfdのみに関心を持つため、サブプロセス領域ではlistenfd(#2)を閉じる必要があります.
さらに、socketのclose()はカウントを採用し、カウントが0の場合にFINを送信するが、shutdown()関数はカウントにかかわらずFINを直接送信することができる.ここではshutdown()は使えないのは明らかです.