Rumah > Artikel > Operasi dan penyelenggaraan > Bagaimana untuk melaksanakan berbilang pelanggan untuk menyambung ke pelayan menggunakan soket linux
1. Pengenalan
Dalam situasi sebenar, orang sering menghadapi berbilang pelanggan yang menyambung ke pelayan. Memandangkan fungsi yang diperkenalkan sebelum ini seperti sambung, recv, hantar, dsb. semuanya adalah fungsi menyekat, jika sumber tidak disediakan sepenuhnya, proses memanggil fungsi akan memasuki keadaan tidur, yang tidak akan dapat mengendalikan pemultipleksan I/O. .
Artikel ini memberikan dua kaedah pemultipleksan I/O: fcntl(), pilih(). Ia dapat dilihat bahawa sejak Linux menganggap soket sebagai deskriptor fail khas, ini membawa kemudahan yang besar kepada pengguna.
2. fcntl
Fungsi fcntl() mempunyai ciri-ciri berikut:
1) I/O tidak menyekat: cmd boleh ditetapkan kepada F_SETFL, Tetapkan kunci kepada O_NONBLOCK
2) I/O dipandu isyarat: Anda boleh tetapkan cmd kepada F_SETFL dan tetapkan kunci kepada O_ASYNC.
Rutin:
#include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/un.h> #include <sys/time.h> #include <sys/ioctl.h> #include <unistd.h> #include <netinet/in.h> #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))<0) perror("fcntl F_SETFL"); flags |= O_NONBLOCK; if(fcntl( sockfd, F_SETFL,flags)<0) perror("fcntl"); while(1){ sin_size=sizeof(struct sockaddr_in); if((client_fd=accept(sockfd,(struct sockaddr*)&client_sockaddr,&sin_size))==-1){ //服务器接受客户端的请求,返回一个新的文件描述符 perror("accept"); exit(1); } if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))==-1){ perror("recv"); exit(1); } if(read(client_fd,buf,MAXDATASIZE)<0){ perror("read"); exit(1); } printf("received a connection :%s",buf); /*关闭连接*/ close(client_fd); exit(1); }/*while*/ }
Jalankan ini Program:
[root@localhost net]# ./fcntl socket success!,sockfd=3 bind success! listening.... accept: Resource temporarily unavailable
Anda dapat melihat bahawa apabila sumber terima tidak tersedia, program akan kembali secara automatik.
Jika anda menggantikan kod tebal merah dengan:
if((flags=fcntl( sockfd, F_SETFL, 0))<0) perror("fcntl F_SETFL"); flags |= O_ASYNC; if(fcntl( sockfd, F_SETFL,flags)<0) perror("fcntl");
Hasil yang dijalankan adalah seperti berikut:
[root@localhost net]# ./fcntl1 socket success!,sockfd = 3 bind success! listening...
Seperti yang anda lihat, prosesnya mempunyai telah menunggu sehingga isyarat lain yang berkaitan memacunya.
3 pilih
#include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/un.h> #include <sys/time.h> #include <sys/ioctl.h> #include <unistd.h> #include <netinet/in.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; 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)<0){ perror("read"); exit(1); } printf("received a connection :%s",buf); }/*if*/ close(client_fd); }/*select*/ }/*while*/ } 运行结果如下: [root@localhost net]# gcc select1.c -o select1 [root@localhost net]# ./select1 socket create success! bind success! listening...
Atas ialah kandungan terperinci Bagaimana untuk melaksanakan berbilang pelanggan untuk menyambung ke pelayan menggunakan soket linux. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!