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 #include #include #include #include #include #include #include #include #include #include #include #include #include #define SERVPORT 3333#define BACKLOG 10#define MAX_CONNECTED_NO 10#define MAXDATASIZE 100int 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]# ./fcntlsocket success!,sockfd=3bind 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]# ./fcntl1socket success!,sockfd = 3bind success!listening...

可以看到,进程一直处于等待中,直到另一相关信号驱动它为止。

三、select

#include #include #include #include #include #include #include #include #include #include #include #include #define SERVPORT 3333#define BACKLOG 10#define MAX_CONNECTED_NO 10#define MAXDATASIZE 100int 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]# ./select1socket create success!bind success!listening...

以上就是linux socket怎么实现多个客户端连接服务器端的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/243330.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月4日 02:31:43
下一篇 2025年11月4日 02:32:30

相关推荐

  • Linux中如何安装Nginx服务_Linux安装Nginx服务的完整指南

    首先更新系统软件包,然后通过对应包管理器安装Nginx,启动并启用服务,开放防火墙端口,最后验证欢迎页显示以确认安装成功。 在Linux系统中安装Nginx服务是搭建Web服务器的第一步。Nginx以高性能、低资源消耗和良好的并发处理能力著称,广泛用于静态内容服务、反向代理和负载均衡。以下是在主流L…

    2025年12月6日 运维
    000
  • Linux journalctl与systemctl status结合分析

    先看 systemctl status 确认服务状态,再用 journalctl 查看详细日志。例如 nginx 启动失败时,systemctl status 显示 Active: failed,journalctl -u nginx 发现端口 80 被占用,结合两者可快速定位问题根源。 在 Lin…

    2025年12月6日 运维
    000
  • Linux如何防止缓冲区溢出_Linux防止缓冲区溢出的安全措施

    缓冲区溢出可通过栈保护、ASLR、NX bit、安全编译选项和良好编码实践来防范。1. 使用-fstack-protector-strong插入canary检测栈破坏;2. 启用ASLR(kernel.randomize_va_space=2)随机化内存布局;3. 利用NX bit标记不可执行内存页…

    2025年12月6日 运维
    000
  • Linux如何优化系统性能_Linux系统性能优化的实用方法

    优化Linux性能需先监控资源使用,通过top、vmstat等命令分析负载,再调整内核参数如TCP优化与内存交换,结合关闭无用服务、选用合适文件系统与I/O调度器,持续按需调优以提升系统效率。 Linux系统性能优化的核心在于合理配置资源、监控系统状态并及时调整瓶颈环节。通过一系列实用手段,可以显著…

    2025年12月6日 运维
    000
  • Pboot插件数据库连接的配置教程_Pboot插件数据库备份的自动化脚本

    首先配置PbootCMS数据库连接参数,确保插件正常访问;接着创建auto_backup.php脚本实现备份功能;然后通过Windows任务计划程序或Linux Cron定时执行该脚本,完成自动化备份流程。 如果您正在开发或维护一个基于PbootCMS的网站,并希望实现插件对数据库的连接配置以及自动…

    2025年12月6日 软件教程
    000
  • Linux命令行中wc命令的实用技巧

    wc命令可统计文件的行数、单词数、字符数和字节数,常用-l统计行数,如wc -l /etc/passwd查看用户数量;结合grep可分析日志,如grep “error” logfile.txt | wc -l统计错误行数;-w统计单词数,-m统计字符数(含空格换行),-c统计…

    2025年12月6日 运维
    000
  • 如何在Linux中使用cron和at定时任务?

    cron用于周期性任务,at用于一次性任务。例如:0 2 * /backup.sh每天凌晨2点备份;echo “shutdown” | at 11:00 PM设置晚上11点关机。使用crontab -e编辑、atq查看、atrm删除任务,注意使用绝对路径、重定向输出并确保at…

    2025年12月6日 运维
    000
  • Linux命令行中fc命令的使用方法

    fc 是 Linux 中用于管理命令历史的工具,可查看、编辑并重新执行历史命令。输入 fc 直接编辑最近一条命令,默认调用 $EDITOR 打开编辑器修改后自动执行;通过 fc 100 110 或 fc -5 -1 可批量编辑指定范围的历史命令,保存后按序重跑;使用 fc -l 列出命令历史,支持起…

    2025年12月6日 运维
    000
  • 如何在Linux中查看磁盘IO性能?

    iostat和iotop是Linux中诊断磁盘IO性能的核心工具,配合df、du和sar可全面分析IO瓶颈与空间压力。 在Linux中查看磁盘IO性能,主要依赖系统自带的命令行工具。这些工具能实时或历史性地展示磁盘读写情况、响应时间、利用率等关键指标,帮助判断是否存在IO瓶颈。 使用 iostat …

    2025年12月6日 运维
    000
  • 如何在Linux中删除文件和目录?

    使用rm命令删除文件,如rm filename;2. rmdir仅删除空目录,如rmdir dirname;3. rm -r递归删除非空目录,rm -rf强制删除且无提示,需谨慎使用。 在Linux中删除文件和目录主要使用rm和rmdir命令,根据需求选择合适的方式操作。 删除文件(rm) 使用rm…

    2025年12月6日 运维
    000
  • 如何在Linux中设置守护进程?

    答案:Linux中设置守护进程推荐使用systemd。编写程序后创建.service文件,配置Unit、Service和Install字段,通过systemctl enable/start启动服务,并用status查看状态;手动实现需fork、setsid、chdir、umask及重定向IO,适用于…

    2025年12月6日 运维
    000
  • VSCode终端美化:功率线字体配置

    首先需安装Powerline字体如Nerd Fonts,再在VSCode设置中将terminal.integrated.fontFamily设为’FiraCode Nerd Font’等支持字体,最后配合oh-my-zsh的powerlevel10k等Shell主题启用完整美…

    2025年12月6日 开发工具
    000
  • Linux命令行中locate命令的快速查找方法

    locate命令通过查询数据库快速查找文件,使用-i可忽略大小写,-n限制结果数量,-c统计匹配项,-r支持正则表达式精确匹配,刚创建的文件需运行sudo updatedb更新数据库才能查到。 在Linux命令行中,locate 命令是快速查找文件和目录路径的高效工具。它不直接扫描整个文件系统,而是…

    2025年12月6日 运维
    000
  • Linux文件系统rsync命令详解

    rsync通过增量同步高效复制文件,支持本地及远程同步,常用选项包括-a、-v、-z和–delete,结合SSH可安全传输数据,配合cron可实现定时备份。 rsync 是 Linux 系统中一个非常强大且常用的文件同步工具,能够高效地在本地或远程系统之间复制和同步文件与目录。它以“增量…

    2025年12月6日 运维
    000
  • Linux systemctl list-dependencies命令详解

    systemctl list-dependencies 用于查看 systemd 单元的依赖关系,帮助排查启动问题和优化启动流程。1. 基本语法为 systemctl list-dependencies [选项] [单元名称],默认显示 default.target 的依赖。2. 常见单元类型包括 …

    2025年12月6日 运维
    000
  • 如何在Linux中挂载NFS共享目录?

    首先确认NFS服务可用,使用showmount -e 192.168.1.100检查共享目录,安装nfs-common或nfs-utils包后创建本地挂载点/mnt/nfs_share,执行sudo mount 192.168.1.100:/shared/data /mnt/nfs_share完成挂…

    2025年12月6日 运维
    000
  • 如何在mysql中安装mysql插件扩展

    安装MySQL插件需先确认插件文件位于plugin_dir目录,使用INSTALL PLUGIN命令加载,如INSTALL PLUGIN keyring_file SONAME ‘keyring_file.so’,并确保用户有SUPER权限,最后通过SHOW PLUGINS验…

    2025年12月6日 数据库
    000
  • 如何在Linux中限制用户磁盘空间?

    在Linux中通过磁盘配额限制用户空间,需先在/etc/fstab中添加usrquota、grpquota选项并重新挂载;2. 使用quotacheck创建aquota.user和aquota.group数据库文件;3. 用edquota设置用户软硬限制,如500MB空间;4. 启用quotaon并…

    2025年12月6日 运维
    000
  • 如何在mysql中定期清理过期备份文件

    通过Shell脚本结合cron定时任务实现MySQL过期备份文件自动清理,首先统一备份命名格式(如backup_20250405.sql)并存放在指定目录(/data/backup/mysql),然后编写脚本使用find命令删除7天前的.sql文件,配置每日凌晨2点执行的cron任务,并加入日志记录…

    2025年12月6日 数据库
    000
  • Linux文件系统中的ext4与xfs对比

    ext4适合通用场景,稳定性强,兼容性好,适用于桌面和中小型服务器;XFS擅长大规模高并发I/O,扩展性强,适用于大文件与高性能需求环境。 在Linux系统中,ext4和XFS是两种广泛使用的文件系统,各自适用于不同的使用场景。选择哪一个取决于性能需求、数据规模以及工作负载类型。 设计目标与适用场景…

    2025年12月6日 运维
    000

发表回复

登录后才能评论
关注微信