1.select的缺点:
1.select监听的文件描述符集合是一个数组,有上限(1024个)
2.select监听的文件描述符集合在应用层,内核层监听事件后需要传递给用户层带来资源开销
3.select需要用户手动查找产生事件的文件描述符
4.select只能工作在水平触发模式(低速模式)而无法工作在边沿触发模式(高速模式)
2.poll
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:
监听文件描述符集合,工作方式类似于select
参数:
fds:文件描述符集合首地址
nfds:文件描述符集合的数组的长度
timeout:超时时间,单位毫秒,-1表示永久等待
返回值:
成功返回产生事件文件描述符个数
失败返回-1
超时仍然没有产生的事件返回0
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
read.c
#include "head.h"
int main(void)
{
int fd = 0;
char tmpbuff[4096] = {0};
struct pollfd fds[2];
int nready = 0;
mkfifo("/tmp/myfifo", 0777);
fd = open("/tmp/myfifo", O_RDONLY);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
fds[0].fd = fd; //要监听的文件描述符
fds[0].events = POLLIN; //要监听的事件
fds[1].fd = 0;
fds[1].events = POLLIN;
while (1)
{
nready = poll(fds, 2, -1);
if (-1 == nready)
{
perror("fail to poll");
return -1;
}
if (fds[0].revents & POLLIN)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fd, tmpbuff, sizeof(tmpbuff));
printf("FIFO:%s\n", tmpbuff);
}
if (fds[1].revents & POLLIN)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
gets(tmpbuff);
printf("STDIN:%s\n", tmpbuff);
}
}
close(fd);
return 0;
}
1.poll的缺点:
1.poll监听的文件描述符集合在应用层,内核层监听事件后需要传递给用户层带来资源开销
2.poll需要用户手动查找产生事件的文件描述符
3.poll只能工作在水平触发模式(低速模式)而无法工作在边沿触发模式(高速模式)
3.epoll
1.epoll_create
int epoll_create(int size);
功能:
在内核层创建一张epoll监听的事件表
参数:
size:监听的事件表大小
返回值:
成功返回新的文件描述符
失败返回-1
2.epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:
管理内核中epoll事件表
参数:
epfd:文件描述符
op: EPOLL_CTL_ADD 添加客户端
EPOLL_CTL_MOD 修改客户端
EPOLL_CTL_DEL 删除客户端
fd:文件描述符
event:事件结构体
返回值:
成功返回0
失败返回-1
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events:EPOLLIN EPOLLOUT EPOLLET
3.epoll_wait
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
功能:
监听epfd对应的事件表中是否有事件发生
参数:
epfd:文件描述符
events:存放产生事件的数组空间首地址
maxevents:最多存放数组元素个数
timeout:超时时间,单位毫秒,-1表示永久等待
返回值:
成功返回实际发生事件的个数
失败返回-1
超时仍然没有产生事件返回0
#include "head.h"
int main(void)
{
int epfd = 0;
int fd = 0;
int ret = 0;
char tmpbuff[4096] = {0};
struct epoll_event env;
struct epoll_event retenv[2];
int nready = 0;
int i = 0;
mkfifo("/tmp/myfifo", 0777);
fd = open("/tmp/myfifo", O_RDONLY);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
//创建一张内核监听的事件表
epfd = epoll_create(2);
if (-1 == epfd)
{
perror("fail to epoll_create");
return -1;
}
//将fd文件描述符加入事件表中
env.events = EPOLLIN;
env.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);
if (-1 == ret)
{
perror("fail to epoll_ctl");
return -1;
}
//将0文件描述符加入事件表中
env.events = EPOLLIN;
env.data.fd = 0;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);
if (-1 == ret)
{
perror("fail to epoll_ctl");
return -1;
}
while (1)
{
nready = epoll_wait(epfd, retenv, 2, -1);
if (-1 == nready)
{
perror("fail to epoll_wait");
return -1;
}
for (i = 0; i < nready; i++)
{
if (retenv[i].data.fd == fd)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
read(fd, tmpbuff, sizeof(tmpbuff));
printf("FIFO:%s\n", tmpbuff);
}
else if (retenv[i].data.fd == 0)
{
memset(tmpbuff, 0, sizeof(tmpbuff));
gets(tmpbuff);
printf("STDIN:%s\n", tmpbuff);
}
}
}
close(epfd);
return 0;
}
epoll的优点:
1.epoll没有文件描述符上限限制
2.epoll监听的事件表在内核层,内核监听事件不需要操作用户层空间提高效率
3.epoll会获得产生事件的文件描述符,不需要用户查找
4.epoll可以工作在边沿触发模式(高速模式),提高效率
1.编写客户端和服务端实现基于UDP的聊天室:
客户端:
1.允许用户输入昵称
2.可以向服务端发送登录消息
3.可以向服务器发送退出消息
4.可以向服务器发送聊天消息
服务端:
1.接收所有客户端的登录消息
2.接收所有客户端的退出消息
3.能够转发所有客户端的聊天消息
2.实现一个基于TCP的单词查询系统:
dict.txt文件
1.编写客户端允许注册、注销、登录到服务器中
2.登录成功后,客户端可以发送给服务器一个单词,并获得单词的含义
3.客户端允许向服务器发送获得历史单词信息
1.服务器响应注册、注销、登录一系列功能
2.服务器响应客户端单词查询和历史搜索单词功能
3.服务器需要支持TCP并发模型,支持多用户的并发请求
//服务端代码
#include "head.h"
int main(int argc, char const *argv[])
{
struct sockaddr_in seraddr;
bzero(&seraddr, sizeof(seraddr));
int 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(50000);
seraddr.sin_addr.s_addr = INADDR_ANY;
int bret = bind(sockfd, (SA)&seraddr, sizeof(seraddr));
if(-1 == bret)
{
perror("fail to bind");
return -1;
}
int lret = listen(sockfd, 10);
if(-1 == lret)
{
perror("fail to listen");
return -1;
}
int serfd = accept(sockfd, NULL, NULL);
if(-1 == serfd)
{
perror("fail to accept");
return -1;
}
FILE *fp = fopen("dict.txt", "r");
if(fp == NULL)
{
perror("fail to fopen");
return -1;
}
char word[128] = {0};
char summar[1024] = {0};
while(1)
{
memset(word, 0, sizeof(word));
fseek(fp, 0, SEEK_SET);
recv(serfd, word, sizeof(word), 0);
printf("%s\n", word);
if(!strcmp(word, "#quit"))
{
break;
}
while(1)
{
memset(summar, 0, sizeof(summar));
char *psum = summar;
char *pret = fgets(summar, sizeof(summar), fp);
if(!strncmp(word, summar, strlen(word)))
{
psum += strlen(word);
while(*psum == ' ')
{
psum++;
}
send(serfd, psum, strlen(psum), 0);
break;
}
if(NULL == pret)
{
char fail[64] = "please enter a correct word, or you can quit!\n";
send(serfd, fail, strlen(fail), 0);
break;
}
}
}
fclose(fp);
close(sockfd);
close(serfd);
return 0;
}
//客户端代码
#include "head.h"
int main(int argc, char const *argv[])
{
struct sockaddr_in seraddr;
bzero(&seraddr, sizeof(seraddr));
int 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(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.0.185");
int conn = connect(sockfd, (SA)&seraddr, sizeof(seraddr));
if(-1 == conn)
{
perror("fail to connect");
return -1;
}
char word[128] = {0};
char mean[1024] = {0};
while(1)
{
memset(word, 0, sizeof(word));
memset(mean, 0, sizeof(mean));
printf("enter a word:");
scanf("%s", word);
if(!strcmp(word, "#quit"))
{
break;
}
send(sockfd, word, strlen(word), 0);
recv(sockfd, mean, sizeof(mean), 0);
printf("%s", mean);
}
close(sockfd);
return 0;
}
//头文件
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif