ホームページ >運用・保守 >Linuxの運用と保守 >Linuxソケットを使用してサーバーに接続する複数のクライアントを実装する方法
1. はじめに
実際の状況では、複数のクライアントがサーバーに接続していることがよくあります。これまでに紹介したconnect、recv、sendなどの関数はすべてブロッキング関数であるため、リソースが十分に準備されていない場合、関数を呼び出したプロセスがスリープ状態になり、I/O多重化に対応できなくなります。 . .
この記事では、 I/O 多重化の 2 つの方法、fcntl()、select() について説明します。 Linux はソケットを特殊なファイル記述子として扱うため、これがユーザーに大きな利便性をもたらしていることがわかります。
2. fcntl
fcntl() 関数には次の特徴があります:
1) ノンブロッキング I/O: cmd を設定できます。に F_SETFL、ロックを O_NONBLOCK に設定
2) シグナル駆動 I/O: cmd を F_SETFL に設定し、ロックを O_ASYNC に設定できます。
ルーチン:
#include <sys> #include <sys> #include <sys> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys> #include <sys> #include <sys> #include <unistd.h> #include <netinet> #include <fcntl.h> #include <unistd.h> #define SERVPORT 3333 #define BACKLOG 10 #define MAX_CONNECTED_NO 10 #define MAXDATASIZE 100 int main() { struct sockaddr_in server_sockaddr,client_sockaddr; int sin_size,recvbytes,flags; int sockfd,client_fd; char buf[MAXDATASIZE]; /*创建socket*/ if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1){ perror("socket"); exit(1); } printf("socket success!,sockfd=%d\n",sockfd); /*设置sockaddr结构*/ server_sockaddr.sin_family=AF_INET; server_sockaddr.sin_port=htons(SERVPORT); server_sockaddr.sin_addr.s_addr=INADDR_ANY; bzero(&(server_sockaddr.sin_zero),8); /*将本地ip地址绑定端口号*/ if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))==-1){ perror("bind"); exit(1); } printf("bind success!\n"); /*监听*/ if(listen(sockfd,BACKLOG)==-1){ perror("listen"); exit(1); } printf("listening....\n"); /*fcntl()函数,处理多路复用I/O*/ if((flags=fcntl( sockfd, F_SETFL, 0))<p data-id="p838747a-v4XAh0T3">Runこのプログラム: <br></p> <pre class="brush:php;toolbar:false">[root@localhost net]# ./fcntl socket success!,sockfd=3 bind success! listening.... accept: Resource temporarily unavailable
accept リソースが利用できない場合、プログラムが自動的に戻ることがわかります。
赤い太字のコードを次のように置き換えると:
if((flags=fcntl( sockfd, F_SETFL, 0))<p data-id="p838747a-AEbYy731">実行結果は次のようになります: <br></p><pre class="brush:php;toolbar:false">[root@localhost net]# ./fcntl1 socket success!,sockfd = 3 bind success! listening...
プロセスが待機していることがわかります。別の関連信号がそれを駆動するまで。
3.select
#include <sys> #include <sys> #include <sys> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys> #include <sys> #include <sys> #include <unistd.h> #include <netinet> #define SERVPORT 3333 #define BACKLOG 10 #define MAX_CONNECTED_NO 10 #define MAXDATASIZE 100 int main() { struct sockaddr_in server_sockaddr,client_sockaddr; int sin_size,recvbytes; fd_set readfd; fd_set writefd; int sockfd,client_fd; char buf[MAXDATASIZE]; /*创建socket*/ if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1){ perror("socket"); exit(1); } printf("socket success!,sockfd=%d\n",sockfd); /*设置sockaddr结构*/ server_sockaddr.sin_family=AF_INET; server_sockaddr.sin_port=htons(SERVPORT); server_sockaddr.sin_addr.s_addr=INADDR_ANY; bzero(&(server_sockaddr.sin_zero),8); /*将本地ip地址绑定端口号*/ if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))==-1){ perror("bind"); exit(1); } printf("bind success!\n"); /*监听*/ if(listen(sockfd,BACKLOG)==-1){ perror("listen"); exit(1); } printf("listening....\n"); /*select*/ FD_ZERO(&readfd); // 将readfd 清空 FD_SET(sockfd,&readfd); //将sockfd加入到readfd集合中 while(1){ sin_size=sizeof(struct sockaddr_in); if(select(MAX_CONNECTED_NO,&readfd,NULL,NULL,(struct timeval(FD_ISSET(sockfd,&readfd)>0){ // FD_ISSET 这个宏判断 sockfd 是否属于可读的文件描述符。从 sockfd 中读入, 输出到标准输出上去. if((client_fd=accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size))==-1){ //client_sockaddr:客户端地址 perror("accept"); exit(1); } if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))==-1){ perror("recv"); exit(1); } if(read(client_fd,buf,MAXDATASIZE)</netinet></unistd.h></sys></sys></sys></string.h></errno.h></stdlib.h></stdio.h></sys></sys></sys>
以上がLinuxソケットを使用してサーバーに接続する複数のクライアントを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。