共计 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 行业资讯频道。