linux socket怎么实现多个客户端连接服务器端

76次阅读
没有评论

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

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-15发表,共计4315字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)