热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下一个单进程并发服务器的实例使用select

nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd

/*单进程并发服务器实例。该程序采用单进程并发服务器算法实现的。*/
#include         
#include          
#include       
#include
#include
#include
#include
#include
#include

#define PORT 1234           //服务器端口
#define BACKLOG 5           //listen队列中等待的连接数
#define MAXDATASIZE 1024 //缓冲区大小

typedef struct _CLIENT{        //客户端结构体
int       fd;        //客户端socket描述符
char*  name;
struct sockaddr_in addr;     //客户端地址信息结构体
char* data;                                      
} CLIENT;
void process_cli(CLIENT *client, char* recvbuf, int len);  //客户请求处理函数
void savedata(char* recvbuf, int len, char* data);

main()
{
int    i, maxi, maxfd,sockfd;
int    nready;
ssize_t      n;
fd_set      rset, allset;    //select所需的文件描述符集合
int listenfd, connectfd;     //socket文件描述符
struct sockaddr_in server;     //服务器地址信息结构体

CLIENT client[FD_SETSIZE];     //FD_SETSIZE为select函数支持的最大描述符个数
char recvbuf[MAXDATASIZE];    //缓冲区
int sin_size;            //地址信息结构体大小

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {    //调用socket创建用于监听客户端的socket
perror("Creating socket failed.");
exit(1);
}

int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    //设置socket属性

bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);

if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {    //调用bind绑定地址
perror("Bind error.");
exit(1);
}  

if(listen(listenfd,BACKLOG) == -1){      //调用listen开始监听
perror("listen() error\n");
exit(1);
}

sin_size=sizeof(struct sockaddr_in);
//初始化select
maxfd = listenfd;    
maxi = -1;              
for (i = 0; i client[i].fd = -1; 
}
FD_ZERO(&allset);        //清空
FD_SET(listenfd, &allset);    //将监听socket加入select检测的描述符集合

while(1)
{
struct sockaddr_in addr;
rset = allset;           
nready = select(maxfd+1, &rset, NULL, NULL, NULL);    //调用select
printf("select saw rset actions and the readfset num is %d. \n",nready );

if (FD_ISSET(listenfd, &rset)) {      //检测是否有新客户端请求
printf("accept a connection.\n");
//调用accept,返回服务器与客户端连接的socket描述符
if ((cOnnectfd= accept(listenfd,(struct sockaddr *)&addr,(socklen_t *)&sin_size))==-1) {
perror("accept() error\n");
continue;
}

//将新客户端的加入数组
for (i = 0; i if (client[i].fd <0) {
client[i].fd = connectfd;    //保存客户端描述符
client[i].name = new char[MAXDATASIZE];
client[i].addr = addr;
client[i].data = new char[MAXDATASIZE];
client[i].name[0] = '\0';
client[i].data[0] = '\0';
printf("You got a connection from %s.  ",inet_ntoa(client[i].addr.sin_addr) );
break;
}
}   

printf("add new connect fd.\n");
if (i == FD_SETSIZE)         
printf("too many clients\n");
FD_SET(connectfd, &allset);   //将新socket连接放入select监听集合
if (connectfd > maxfd) 
maxfd = connectfd;   //确认maxfd是最大描述符
if (i > maxi)          //数组最大元素值
maxi = i;         
if (--nready <= 0)
continue;      //如果没有新客户端连接,继续循环
}

for (i = 0; i <= maxi; i++) {    
if ( (sockfd = client[i].fd) <0)       //如果客户端描述符小于0,则没有客户端连接,检测下一个
continue;

if (FD_ISSET(sockfd, &rset)) {        //检测此客户端socket是否有数据   
printf("recv occured for connect fd[%d].\n",i);
if ( (n = recv(sockfd, recvbuf, MAXDATASIZE,0)) == 0) { //从客户端socket读数据,等于0表示网络中断
close(sockfd);        //关闭socket连接
printf("Client( %s ) closed connection. User's data: %s\n",client[i].name,client[i].data);
FD_CLR(sockfd, &allset);    //从监听集合中删除此socket连接
client[i].fd = -1;        //数组元素设初始值,表示没客户端连接
delete client[i].name;
delete client[i].data;
} else
process_cli(&client[i], recvbuf, n);    //接收到客户数据,开始处理
if (--nready <= 0)    
break;       //如果没有新客户端有数据,跳出for循环回到while循环
}
}
}
close(listenfd);  //关闭服务器监听socket    
}

void process_cli(CLIENT *client, char* recvbuf, int len)
{
char sendbuf[MAXDATASIZE];

recvbuf[len-1] = '\0';
if (strlen(client->name) == 0) {
memcpy(client->name,recvbuf, len);
printf("Client's name is %s.\n",client->name);
return;
}

printf("Received client( %s ) message: %s\n",client->name, recvbuf);
savedata(recvbuf,len, client->data);
for (int i1 = 0; i1 sendbuf[i1] = recvbuf[len - i1 -2];
}
sendbuf[len - 1] = '\0';

send(client->fd,sendbuf,strlen(sendbuf),0);
}

void savedata(char* recvbuf, int len, char* data)
{
int start = strlen(data);
for (int i = 0; i data[start + i] = recvbuf[i];
}       
}


推荐阅读
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 这篇文章主要介绍了Python拼接字符串的七种方式,包括使用%、format()、join()、f-string等方法。每种方法都有其特点和限制,通过本文的介绍可以帮助读者更好地理解和运用字符串拼接的技巧。 ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • BZOJ1233 干草堆单调队列优化DP
    本文介绍了一个关于干草堆摆放的问题,通过使用单调队列来优化DP算法,求解最多可以叠几层干草堆。具体的解题思路和转移方程在文章中进行了详细说明,并给出了相应的代码示例。 ... [详细]
  • 数据结构与算法的重要性及基本概念、存储结构和算法分析
    数据结构与算法在编程领域中的重要性不可忽视,无论从事何种岗位,都需要掌握数据结构和算法。本文介绍了数据结构与算法的基本概念、存储结构和算法分析。其中包括线性结构、树结构、图结构、栈、队列、串、查找、排序等内容。此外,还介绍了图论算法、贪婪算法、分治算法、动态规划、随机化算法和回溯算法等高级数据结构和算法。掌握这些知识对于提高编程能力、解决问题具有重要意义。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
author-avatar
4396
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有