今天主要学习了TCP并发模型,并且理解了TCP多线程模型的缺点,最主要的就是:创建线程会带来资源开销,能够实现的并发量比较有限
IO模型
IO模型主要分为4类,分别是:
1.阻塞IO:
没有数据到来时,可以让任务挂起,节省CPU资源开销,提高系统效率
2.非阻塞IO:
程序未接收到数据时一直执行,效率很低
3.异步IO:
只能绑定一个文件描述符用来读取数据
4.多路复用IO:
select
1.select监听的集合中的文件描述符有上限限制
2.select有内核层向用户层数据空间拷贝的过程,占用系统资源开销
3.select必须轮询检测产生事件的文件描述符
4.select只能工作在水平触发模式(低速模式),无法工作在边沿触发(高速模式)
poll
1.poll有内核层向用户层数据空间拷贝的过程,占用系统资源开销
2.poll必须轮询检测产生事件的文件描述符
3.poll只能工作在水平触发模式(低速模式),无法工作在边沿触发(高速模式)
epoll :这个明天来讲
主要介绍一下关于TCP多路复用IO
在多路复用中,其client.c一样,所以在这里把代码写一下,在下面只写客户端的代码
client.c代码
#include "head.h"
int CreateTcpClient(char *pip, int port) //链接tcp
{
int ret = 0;
int sockfd = 0;
struct sockaddr_in seraddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); //参数1:IPv4协议族;参数2:数据报套接字;参数3:协议,默认为0
if (-1 == sockfd)
{
perror("fail to socket");
return -1;
}
seraddr.sin_family = AF_INET; //IPv4模式
seraddr.sin_port = htons(port); //将端口50000转为网络的大端模式
seraddr.sin_addr.s_addr = inet_addr(pip); //将字符串IP地址转为内存中的IP地址
ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
if (-1 == ret)
{
perror("fail to connect");
return -1;
}
return sockfd;
}
int main(void)
{
int sockfd = 0;
char tmpbuff[4096] = {
0};
int cnt = 0;
ssize_t nsize = 0;
sockfd = CreateTcpClient("192.168.1.152", 50000);
while (1)
{
memset(tmpbuff, 0, sizeof(tmpbuff)); //清零操作
sprintf(tmpbuff, "hello world --- %d", cnt);
cnt++;
nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0); //发送
if (-1 == nsize)
{
perror("fail to send");
return -1;
}
memset(tmpbuff, 0, sizeof(tmpbuff));
nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0); //接收
if (-1 == nsize)
{
perror("fail to recv");
return -1;
}
printf("RECV:%s\n", tmpbuff);
}
close(sockfd);
return 0;
}
select
select
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:
select监听文件描述符集合中是否有文件描述编程ready状态
功能:
nfds:最大文件描述符的值+1
readfds:读文件描述符集合
writefds:写文件描述符集合
exceptfds:其余文件描述符集合
timeout:等待的时长
NULL 一直等待
返回值:
成功返回文件描述符集合中的文件描述符个数
失败返回-1
void FD_CLR(int fd, fd_set *set);
功能:
将文件描述符fd从集合中清除
int FD_ISSET(int fd, fd_set *set);
功能:
判断文件描述符fd是否仍在集合中
void FD_SET(int fd, fd_set *set);
功能:
将文件描述符fd加入到集合中
void FD_ZERO(fd_set *set);
功能:
将文件描述符集合清0
eg:
server.c代码
#include"head.h"
int CreateListenSocket(char *pip,int port)
{
int ret = 0;
int sockfd = 0;
struct sockaddr_in seraddr;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("fail to socket");
return -1;
}
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(port);
seraddr.sin_addr.s_addr = inet_addr(pip);
ret = bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));
if(-1 == ret)
{
perror("fail to bind");