一、并发服务器模型
【1】 循环服务器
1>一次只能处理一个客户端的请求,等待这个客户端退出后,才能处理下一个客户端
2>缺点:循环服务器所处理的客户端不能有耗时操作
//*****模型******
sfd = socket();
bind();
listen();
while(1)
{
newfd = accept();
while(1)
{
recv();
send();
}
close(newfd);
}
close(sfd);
【2】并发服务器
1>可以同时处理多个客户端请求
2>父进程 / 主线程专门用于负责连接,创建子进程 / 分支线程用来与客户端交互
~多线程:
//*****模型******
sfd = socket();
bind();
listen();
while(1)
{
newfd = accept();pthread_create();
pthread_detach(tid);
}
close(sfd);
void * callBack(void * arg)
{
recv();
send();
close(newfd);pthread_exit(NULL);
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_MSG(msg) do{
fprintf(stderr,"liine %d",__LINE__);
perror(msg);
}while(0)
#define IP "192.168.0.79" //本机IP
#define PORT 6666 // 1024-49151
void* deal_cli_msg(void *arg);
//需要传递给线程处理函数的参数
struct cli_msg
{
int newfd;
struct sockaddr_in cin;
};
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfdnewfd;
struct sockaddr_in cin=((struct cli_msg*)arg)->cin;
char buf[128]="";
ssize_t res=0;
while(1)
{
//接收
res=recv(newfd,buf,sizeof(buf),0);
if(res
二、IO模型
【1】阻塞IO
创建套接字文件描述符后,默认处于阻塞IO模式 (read, write, recv, send, recvfrom, sendto)
【2】阻塞IO
1>防止进程阻塞在IO函数上,但是如果想要获取到有效数据,需要轮询
2>当一个程序使用了非阻塞IO模式的套接字,那么它需要使用一个循环来不停地判断该文件描述符是否有数据可读,称之为 polling
3>应用程序不停地polling 内核监测IO 事件是否产生, CPU消耗高
1)fcntl 函数
【3】信号驱动IO
1>异步通信方式
2>信号驱动IO是指:预先告诉内核,某个文件描述符发生IO事件的时候,内核会通知相关进程: SIGIO
3> 对于TCP而言,信号驱动IO对TCP没有用,因为信号产生过于频繁,而且不能区分是哪个文件描述符发送的
【4】IO 多路复用(重点)
1>进程中如果同时需要处理多路输入输出流,在使用单进程单线程的情况下,同时处理多个输入输出请求
2>在无法用多进程多线程,可以选择用IO多路复用
3>由于不需要创建建新的进程和线程,减少系统的资源开销,减少上下文切换的次数
4>允许同时对多个IO进行操作,内核一旦发现进程执行一个或多个IO 事件,会通知该进程。
1)select
模型:
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_MSG(msg) do{
fprintf(stderr,"liine %d",__LINE__);
perror(msg);
}while(0)
#define IP "192.168.0.211" //本机IP
#define PORT 6666 // 1024-49151
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd>");
int sndfd=-1;
res=scanf("%d %s",&sndfd,buf);
while(getchar()!=10);
if(res!=2)
{
fprintf(stderr,"请输入正确格式:int stringn");
continue;
}
//能运行到当前位置,则代表输入的格式整数
if(sndfd=1024||!FD_ISSET(sndfd,&readfds))
{
fprintf(stderr,"sndfd=%d文件描述符n",sndfd);
continue;
}
if(send(sndfd,buf,sizeof(buf),0)>");
fflush(stdout);
int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfdnewfd?maxfd:newfd;
}
else
{
bzero(buf,sizeof(buf));
//接收
res=recv(i,buf,sizeof(buf),0);
if(res=0;j--)
{
if(FD_ISSET(j,&readfds))
{
maxfd=j;
break;
}
}
if(j
2)poll
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_MSG(msg) do{
fprintf(stderr,"liine %d",__LINE__);
perror(msg);
}while(0)
#define IP "192.168.0.211" //本机IP
#define PORT 6666 // 1024-49151
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
printf("%sn",buf);
}
else if(sfd==1)
{
printf("触发客户端连接事件>>");
fflush(stdout);
int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfdnewfd?maxfd:newfd;
}
else
{
bzero(buf,sizeof(buf));
//接收
res=recv(i,buf,sizeof(buf),0);
if(res=0;j--)
{
if(FD_ISSET(j,&readfds))
{
maxfd=j;
break;
}
}
if(j
三、函数库
【1】库的概念
1>库是一个二进制可执行文件,相比较于二进制可执行程序,库是不能单独运行的。
a. 库中存放的都是功能函数,只能放功能函数
b. 库中不允许存放main函数
c.库是写好的,可以被服用的功能代码
2>库需要被载入到内存中使用
3>每个操作系统都有自己得库,不兼容
库的分类:
静态库、动态库
【2】静态库
1)静态库原理:通过静态库封装的函数,在程序编译到链接库步骤的时候,会将函数继承到可执行程序中。
优点: 1>程序运行的时候,与静态库没有任何关系,方便移植
2>静态库的运行效率会更快
缺点:1>程序的更新部署比较麻烦
2>大、存储的时候浪费磁盘空间,加载运行的时候浪费内存空间
2)静态库地 制作指令
步骤:
1>分文件,将功能函数与主函数分离,func.c main.c
2>给功能函数写头文件:func.h
3>将main.c 和 func.c 联合编译,测试分文件是否成功
4>用上述指令将func.c 封装成静态库
5>注意:libxxx.a , xxx才是库的名字
3)静态库的使用
【3】动态库(共享库)
1)动态库的原理:动态库把库函数的链接步骤推迟到程序运行的时候,当程序执行到库函数的时候,会去找动态库函数
1>如果在内存中不存在该动态库函数,则会将动态库函数加载到内存中执行
2>如果在内存中存在该动态库函数,则直接调用,不会加载第二份
3>所以内存中会仅存在一份动态库函数
优点:
1>小、存储的时候节省磁盘空间,运行的时候节省内存空间
2>程序的更新部署比较方便,不需要重新编译可执行程序
缺点:
1>程序运行的时候,如果没有找到动态库,则会导致程序崩溃,所以用动态库生成二进制程序移植性低
2>运行效率低
2)动态库的制作指令
步骤:
1>分文件,将功能函数与主函数分离,func.c main.c
2>给功能函数写头文件:func.h
3>将main.c 和 func.c 联合编译,测试分文件是否成功
4>用上述指令将func.c 封装成静态库
5>注意:libxxx.so , xxx才是库的名字
3)动态库的使用
4)动态库的环境变量配置
1> 将动态库移动到 / lib/或者 /usr/lib 目录下
a. sudo mv ./libmyfunc.so /usr/lib/
b. sudo mv libmyfunc.so/lib/
2>配置环境变量:LD_LIBRARY_PATH
3>修改环境变刘昂的配置文件
a. cd / ec/ld.so.conf.d/
b. sudo touch my.conf 创建一个 .conf结尾的文件
c. sudo vim my.conf
d. 将动态库所在的文件夹的绝对路径填写进去,注意一行只能填写一个动态库的绝对路径
e. 保存退出后,执行sudo ldconfig 刷新环境变量
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net