共計 4315 個字符,預計需要花費 11 分鐘才能閱讀完成。
這篇“linux socket 怎么實現多個客戶端連接服務器端”文章的知識點大部分人都不太理解,所以丸趣 TV 小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“linux socket 怎么實現多個客戶端連接服務器端”文章吧。
一、引言
在實際情況中,人們往往遇到多個客戶端連接服務器端的情況。由于之前介紹的函數如 connect,recv,send 等都是阻塞性函數,若資源沒有充分準備好,則調用該函數的進程將進入睡眠狀態,這樣就無法處理 I / O 多路復用的情況了。
本文給出兩種 I / O 多路復用的方法:fcntl(),select()。可以看到,由于 Linux 中把 socket 當作一種特殊的文件描述符,這給用戶的處理帶來很大方便。
二、fcntl
fcntl() 函數有如下特性:
1)非阻塞 I /O:可將 cmd 設為 F_SETFL, 將 lock 設為 O_NONBLOCK
2) 信號驅動 I /O:可將 cmd 設為 F_SETFL, 將 lock 設為 O_ASYNC.
例程:
#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*/
}
運行該程序:
[root@localhost net]# ./fcntl
socket success!,sockfd=3
bind success!
listening....
accept: Resource temporarily unavailable
可以看到,當 accept 的資源不可用時,程序會自動返回。
若將紅色加粗代碼替換為:
if((flags=fcntl( sockfd, F_SETFL, 0)) 0)
perror( fcntl F_SETFL
flags |= O_ASYNC;
if(fcntl( sockfd, F_SETFL,flags) 0)
perror(fcntl
運行結果如下:
[root@localhost net]# ./fcntl1
socket success!,sockfd = 3
bind success!
listening...
可以看到,進程一直處于等待中,直到另一相關信號驅動它為止。
三、select
#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...
以上就是關于“linux socket 怎么實現多個客戶端連接服務器端”這篇文章的內容,相信大家都有了一定的了解,希望丸趣 TV 小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注丸趣 TV 行業資訊頻道。