1、关于字节排序 网际协议采用大端字节序,来传输多字节整数。 系统提供了转换的宏定义,如果主机与网际协议相同,则宏定义为空。
2、客户端 socket -> connect(阻塞,三次握手)-> rcv
3、服务器端 socket -> bind -> listen -> accept(阻塞,三次握手)-> send4、函数介绍
a..socket
1)函数原型 int socket(int family, int type, int protocol)
2)参数: family: 协议族AF_INET,IPv4协议 ... type : type 套接字类型SOCK_STREAM 字节流套接字 protocol: IPPROCO_TCP IPPROCO_UDP IPPROCO_SCTP
3)返回值 成功:返回套接字符 错误:返回INVALID_SOCKET(-1)
4)示例
[cpp] view plain copy print ?
- #include
- #include
- #include
- int main()
- {
- int socketfd;
- struct sockaddr_in servaddr;
-
- if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- return -1;
- }
- }
#include
#include
#include
int main()
{
int socketfd;
struct sockaddr_in servaddr;
if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
return -1;
}
}
b..connect
1)函数原型 int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
2)参数:
sockfd: socket 函数返回的套接字描述符
servaddr : 服务器的IP和端口
addrlen: 长度(sizeof(servaddr))
3)返回值
成功:0
错误:返回INVALID_SOCKET(-1)
4)示例
[cpp] view plain copy print ?
- #include
- #include
- #include
- #include
- #include
-
- int main()
- {
- int socketfd;
- struct sockaddr_in servaddr;
-
- if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- printf("socket error\n");
- return -1;
- }
-
- bzero(&servaddr, sizeof(servaddr));
-
- servaddr.sin_addr.s_addr = inet_addr("192.168.0.218");
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(55000);
-
- if(connect(socketfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
- {
- printf("connect error\n");
- }
-
- return 0;
- }
#include
#include
#include
#include
#include
int main()
{
int socketfd;
struct sockaddr_in servaddr;
if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("socket error\n");
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_addr.s_addr = inet_addr("192.168.0.218");
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(55000);
if(connect(socketfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
{
printf("connect error\n");
}
return 0;
}
c..bind
1)函数原型 int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
2)参数:
sockfd: socket 函数返回的套接字描述符
servaddr : 服务器的IP和端口
addrlen: 长度(sizeof(servaddr))
3)返回值
成功:0
错误:返回INVALID_SOCKET(-1)
d..listen
1)函数原型 int listen(int sockfd, int backlog)
2)参数:
sockfd: socket 函数返回的套接字描述符
backlog : 内核中套接字排队的最大个数
3)返回值
成功:0
错误:返回INVALID_SOCKET
e..accept
1)函数原型 int accept(int sockfd, const struct sockaddr *servaddr, socklen_t *addrlen)
2)参数:
sockfd: socket 函数返回的套接字描述符
3)返回值
servaddr : 客户进程的IP和端口(可设为null)
addrlen: 长度(sizeof(servaddr))(可设为null)
成功:从监听套接字返回已连接套接字
错误:
如果对客户信息不感兴趣,后两个参数可以置空。
4)示例
[cpp] view plain copy print ?
- #include
- #include
- #include
- #include
- #include
-
- int main()
- {
- int count = 0;
- int listenfd, socketfd;
- int nread;
- struct sockaddr_in servaddr;
- struct timeval timeoutval;
- char readbuf[256];
-
- printf("accept started\n");
-
-
- if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- printf("socket error\n");
- return -1;
- }
-
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(59000);
-
-
- if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- {
- printf("bind error\n");
-
- }
-
-
- listen(listenfd, 5);
-
-
- socketfd = accept(listenfd, NULL, NULL);
-
-
-
- while(1)
- {
- printf("start receive %d...\n", count++);
- memset(readbuf, sizeof(readbuf), 0);
-
- nread = recv(socketfd, readbuf, 10, 0);
- if(nread>0)
- {
- readbuf[10] = '\0';
- printf("receiveed %s, nread = %d\n\n", readbuf, nread);
- }
- }
-
- return 0;
- }
#include
#include
#include
#include
#include
int main()
{
int count = 0;
int listenfd, socketfd;
int nread;
struct sockaddr_in servaddr;
struct timeval timeoutval;
char readbuf[256];
printf("accept started\n");
//socket
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("socket error\n");
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(59000);
//bind
if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("bind error\n");
//return -1;
}
//listen
listen(listenfd, 5);
//accept
socketfd = accept(listenfd, NULL, NULL);
while(1)
{
printf("start receive %d...\n", count++);
memset(readbuf, sizeof(readbuf), 0);
nread = recv(socketfd, readbuf, 10, 0);
if(nread>0)
{
readbuf[10] = '\0';
printf("receiveed %s, nread = %d\n\n", readbuf, nread);
}
}
return 0;
}
/**************************************************************
从 I/O 事件分派机制来看,使用 select()是不合适的,因为它所支持的并发连接数有限(通
常在 1024 个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的 TCP 并发
数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在 I/O 事
件分派不均,导致部分 TCP 连接上的 I/O 出现“饥饿”现象。而如果使用 epoll 或 AIO,则没
有上述问题(早期 Linux 内核的 AIO 技术实现是通过在内核中为每个 I/O 请求创建一个线程来
实现的,这种实现机制在高并发 TCP 连接的情形下使用其实也有严重的性能问题。但在最新的
Linux 内核中,AIO 的实现已经得到改进)。
支持一个进程打开大数目的 socket 描述符(FD)select 最不能忍受的是一个进程所打开的
FD 是有一定限制的,由 FD_SETSIZE 设置,默认值是 2048。对于那些需要支持的上万连接数目
的 IM 服务器来说显然太少了。
这时候你一是可以选择修改这个宏然后重新编译内核,不过资料
也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache 方
案),不过虽然 linux 上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步
远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll 则没有这个限制,它所
支持的 FD 上限是最大可以打开文件的数目,这个数字一般远大于 2048,举个例子,在 1GB 内存
的机器上大约是 10 万左右,具体数目可以 cat /proc/sys/fs/file-max 察看,一般来说这个数
目和系统内存关系很大。
******************************************************************/
5. select函数
1)函数原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
2)参数:
sockfd: socket 函数返回的套接字描述符
readfds : 读描述符集合
writefds: 写描述符集合
errorfds: 错误描述符集合
timeout: 超时
3)返回值
成功:返回值 0:无 >0:描述符就绪的总位数
错误:返回INVALID_SOCKET(-1)
4)包含头文件: include
include
5)示例
[cpp] view plain copy print ?
-
-
-
- #include "select.h"
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr;
- } CLIENT;
-
- #define MYPORT 59000
-
-
- #define BACKLOG 5
-
-
- CLIENT client[BACKLOG];
-
-
- int currentClient = 0;
-
-
- #define REVLEN 10
- char recvBuf[REVLEN];
-
- void showClient();
-
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- struct timeval timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
-
- for(i=0; i
- {
- client[i].fd = -1;
- }
-
-
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
-
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
-
-
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
-
- for(i=0; i
- {
- client[i].fd = -1;
- }
-
-
- while(1)
- {
- FD_ZERO(&readfds);
- FD_SET(sockListen, &readfds);
- sockMax = sockListen;
-
-
- for(i=0; i
- {
- if(client[i].fd >0)
- {
- FD_SET(client[i].fd, &readfds);
- if(sockMax
- sockMax = client[i].fd;
- }
- }
-
- timeout.tv_sec=3;
- timeout.tv_usec=0;
-
- ret = select((int)sockMax+1, &readfds, NULL, NULL, &timeout);
- if(ret < 0)
- {
- printf("select error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
- printf("test111\n");
-
-
- for(i=0; i
- {
- if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds))
- {
- if(recvLen != REVLEN)
- {
- while(1)
- {
-
- ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- client[i].fd = -1;
- recvLen = 0;
- break;
- }
-
- recvLen = recvLen+ret;
- if(recvLen
- {
- continue;
- }
- else
- {
-
- printf("%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf);
-
-
- recvLen = 0;
- break;
- }
- }
- }
- }
- }
-
-
- if(FD_ISSET(sockListen, &readfds))
- {
- printf("isset\n");
- sockSvr = accept(sockListen, NULL, NULL);
-
- if(sockSvr == -1)
- {
- printf("accpet error\n");
- }
- else
- {
- currentClient++;
- }
-
- for(i=0; i
- {
- if(client[i].fd < 0)
- {
- client[i].fd = sockSvr;
- client[i].addr = client_addr;
- printf("You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) );
- break;
- }
- }
-
- }
- }
-
- printf("test\n");
- return 0;
- }
-
-
- void showClient()
- {
- int i;
- printf("client count = %d\n", currentClient);
-
- for(i=0; i
- {
- printf("[%d] = %d", i, client[i].fd);
- }
- printf("\n");
- }
/* 实现功能:通过select处理多个socket
* 监听一个端口,监听到有链接时,添加到select的w.
*/
#include "select.h"
#include
#include
#include
#include
#include
#include
typedef struct _CLIENT{
int fd;
struct sockaddr_in addr; /* client's address information */
} CLIENT;
#define MYPORT 59000
//最多处理的connect
#define BACKLOG 5
//最多处理的connect
CLIENT client[BACKLOG];
//当前的连接数
int currentClient = 0;
//数据接受 buf
#define REVLEN 10
char recvBuf[REVLEN];
//显示当前的connection
void showClient();
int main()
{
int i, ret, sinSize;
int recvLen = 0;
fd_set readfds, writefds;
int sockListen, sockSvr, sockMax;
struct timeval timeout;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
for(i=0; i0)
{
FD_SET(client[i].fd, &readfds);
if(sockMax0 && FD_ISSET(client[i].fd, &readfds))
{
if(recvLen != REVLEN)
{
while(1)
{
//recv数据
ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
if(ret == 0)
{
client[i].fd = -1;
recvLen = 0;
break;
}
else if(ret < 0)
{
client[i].fd = -1;
recvLen = 0;
break;
}
//数据接受正常
recvLen = recvLen+ret;
if(recvLen
6. poll函数
1)函数原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
2)参数:
sockfd: socket 函数返回的套接字描述符
readfds : 读描述符集合
writefds: 写描述符集合
errorfds: 错误描述符集合
timeout: 超时
3)返回值
成功:返回值 0:无 >0:描述符就绪的总位数
错误:返回INVALID_SOCKET(-1)
4)包含头文件: include include
5) 示例
[cpp] view plain copy print ?
-
-
-
- #include "select.h"
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr;
- } CLIENT;
-
- #define MYPORT 59000
-
-
- #define BACKLOG 5
-
-
- int currentClient = 0;
-
-
- #define REVLEN 10
- char recvBuf[REVLEN];
-
- #define OPEN_MAX 1024
-
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- int timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
-
- struct pollfd clientfd[OPEN_MAX];
-
-
-
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
-
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
-
-
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
-
-
-
- clientfd[0].fd = sockListen;
- clientfd[0].events = POLLIN;
- sockMax = 0;
- for(i=1; i
- {
- clientfd[i].fd = -1;
- }
-
-
- while(1)
- {
- timeout=3000;
-
- ret = poll(clientfd, sockMax+1, timeout);
-
- if(ret < 0)
- {
- printf("select error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
-
- if (clientfd[0].revents & POLLIN)
- {
- sockSvr = accept(sockListen, NULL, NULL);
-
- if(sockSvr == -1)
- {
- printf("accpet error\n");
- }
- else
- {
- currentClient++;
- }
-
- for(i=0; i
- {
- if(clientfd[i].fd<0)
- {
- clientfd[i].fd = sockSvr;
- break;
- }
- }
- if(i==OPEN_MAX)
- {
- printf("too many connects\n");
- return -1;
- }
- clientfd[i].events = POLLIN;
- if(i>sockMax)
- sockMax = i;
- }
-
-
- for(i=1; i<=sockMax; i++)
- {
- if(clientfd[i].fd < 0)
- continue;
-
- if (clientfd[i].revents & (POLLIN | POLLERR))
- {
- if(recvLen != REVLEN)
- {
- while(1)
- {
-
- ret = recv(clientfd[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- clientfd[i].fd = -1;
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- clientfd[i].fd = -1;
- recvLen = 0;
- break;
- }
-
- recvLen = recvLen+ret;
- if(recvLen
- {
- continue;
- }
- else
- {
-
- printf("buf = %s\n", recvBuf);
-
-
- recvLen = 0;
- break;
- }
- }
- }
- }
- }
- }
-
- return 0;
- }
/* 实现功能:通过poll, 处理多个socket
* 监听一个端口,监听到有链接时,添加到poll.
*/
#include "select.h"
#include
#include
#include
#include
#include
#include
#include
typedef struct _CLIENT{
int fd;
struct sockaddr_in addr; /* client's address information */
} CLIENT;
#define MYPORT 59000
//最多处理的connect
#define BACKLOG 5
//当前的连接数
int currentClient = 0;
//数据接受 buf
#define REVLEN 10
char recvBuf[REVLEN];
#define OPEN_MAX 1024
int main()
{
int i, ret, sinSize;
int recvLen = 0;
fd_set readfds, writefds;
int sockListen, sockSvr, sockMax;
int timeout;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct pollfd clientfd[OPEN_MAX];
//socket
if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket error\n");
return -1;
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(MYPORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//bind
if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
{
printf("bind error\n");
return -1;
}
//listen
if(listen(sockListen, 5) < 0)
{
printf("listen error\n");
return -1;
}
//clientfd 初始化
clientfd[0].fd = sockListen;
clientfd[0].events = POLLIN; //POLLRDNORM;
sockMax = 0;
for(i=1; isockMax)
sockMax = i;
}
//读取数据
for(i=1; i<=sockMax; i++)
{
if(clientfd[i].fd < 0)
continue;
if (clientfd[i].revents & (POLLIN | POLLERR))//POLLRDNORM
{
if(recvLen != REVLEN)
{
while(1)
{
//recv数据
ret = recv(clientfd[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
if(ret == 0)
{
clientfd[i].fd = -1;
recvLen = 0;
break;
}
else if(ret < 0)
{
clientfd[i].fd = -1;
recvLen = 0;
break;
}
//数据接受正常
recvLen = recvLen+ret;
if(recvLen
6. epoll函数
2. 常用模型的缺点
如果不摆出来其他模型的缺点,怎么能对比出 Epoll 的优点呢。
2.1 PPC/TPC 模型
这两种模型思想类似,就是让每一个到来的连接一边自己做事去,别再来烦我 。只是 PPC 是为它开了一个进程,而 TPC 开了一个线程。可是别烦我是有代价的,它要时间和空间啊,连接多了之后,那么多的进程 / 线程切换,这开销就上来了;因此这类模型能接受的最大连接数都不会高,一般在几百个左右。
2.2 select 模型
1. 最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Select 模型的最大并发数就被相应限制了。自己改改这个 FD_SETSIZE ?想法虽好,可是先看看下面吧 …
2. 效率问题, select 每次调用都会线性扫描全部的 FD 集合,这样效率就会呈现线性下降,把 FD_SETSIZE 改大的后果就是,大家都慢慢来,什么?都超时了??!!
3. 内核 / 用户空间 内存拷贝问题,如何让内核把 FD 消息通知给用户空间呢?在这个问题上 select 采取了内存拷贝方法。
2.3 poll 模型
基本上效率和 select 是相同的, select 缺点的 2 和 3 它都没有改掉。
3. Epoll 的提升
把其他模型逐个批判了一下,再来看看 Epoll 的改进之处吧,其实把 select 的缺点反过来那就是 Epoll 的优点了。
3.1. Epoll 没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于 2048, 一般来说这个数目和系统内存关系很大 ,具体数目可以 cat /proc/sys/fs/file-max 察看。
3.2. 效率提升, Epoll 最大的优点就在于它只管你“活跃”的连接 ,而跟连接总数无关,因此在实际的网络环境中, Epoll 的效率就会远远高于 select 和 poll 。
3.3. 内存拷贝, Epoll 在这点上使用了“共享内存 ”,这个内存拷贝也省略了。
4. Epoll 为什么高效
Epoll 的高效和其数据结构的设计是密不可分的,这个下面就会提到。
首先回忆一下 select 模型,当有 I/O 事件到来时, select 通知应用程序有事件到了快去处理,而应用程序必须轮询所有的 FD 集合,测试每个 FD 是否有事件发生,并处理事件;代码像下面这样:
int res = select(maxfd+1, &readfds, NULL, NULL, 120);
if (res > 0)
{
for (int i = 0; i < MAX_CONNECTION; i++)
{
if (FD_ISSET(allConnection[i], &readfds))
{
handleEvent(allConnection[i]);
}
}
}
// if(res == 0) handle timeout, res < 0 handle error
Epoll 不仅会告诉应用程序有I/0 事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD 集合。
int res = epoll_wait(epfd, events, 20, 120);
for (int i = 0; i < res;i++)
{
handleEvent(events[n]);
}
5. Epoll 关键数据结构
前面提到 Epoll 速度快和其数据结构密不可分,其关键数据结构就是:
struct epoll_event {
__uint32_t events; // Epoll events
epoll_data_t data; // User data variable
};
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
可见 epoll_data 是一个 union 结构体 , 借助于它应用程序可以保存很多类型的信息 :fd 、指针等等。有了它,应用程序就可以直接定位目标了。
6. 使用 Epoll
既然 Epoll 相比 select 这么好,那么用起来如何呢?会不会很繁琐啊 … 先看看下面的三个函数吧,就知道 Epoll 的易用了。
int epoll_create(int size);
生成一个 Epoll 专用的文件描述符,其实是申请一个内核空间,用来存放你想关注的 socket fd 上是否发生以及发生了什么事件。 size 就是你在这个 Epoll fd 上能关注的最大 socket fd 数,大小自定,只要内存足够。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );
控制某个 Epoll 文件描述符上的事件:注册、修改、删除。其中参数 epfd 是 epoll_create() 创建 Epoll 专用的文件描述符。相对于 select 模型中的 FD_SET 和 FD_CLR 宏。
op:EPOLL_CTL_ADD
Register the target file descriptor fd on the epoll instance
EPOLL_CTL_MOD
Change the event event associated with the target file descriptor fd.
EPOLL_CTL_DEL
Remove (deregister) the target file descriptor fd from the epoll instance
int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
等待 I/O 事件的发生;参数说明:
epfd: 由 epoll_create() 生成的 Epoll 专用的文件描述符;
epoll_event: 用于回传代处理事件的数组;
maxevents: 每次能处理的事件数;
timeout: 等待 I/O 事件发生的超时值,单位 ms
返回发生事件数。
相对于 select 模型中的 select 函数。
[cpp] view plain copy print ?
-
-
-
- #include "select.h"
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct _CLIENT{
- int fd;
- struct sockaddr_in addr;
- } CLIENT;
-
- #define MYPORT 59000
-
-
- #define MAX_EVENTS 500
-
-
- int currentClient = 0;
-
-
- #define REVLEN 10
- char recvBuf[REVLEN];
-
-
-
- int epollfd;
-
- struct epoll_event eventList[MAX_EVENTS];
-
- void AcceptConn(int srvfd);
- void RecvData(int fd);
-
- int main()
- {
- int i, ret, sinSize;
- int recvLen = 0;
- fd_set readfds, writefds;
- int sockListen, sockSvr, sockMax;
- int timeout;
- struct sockaddr_in server_addr;
- struct sockaddr_in client_addr;
-
-
- if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- printf("socket error\n");
- return -1;
- }
-
- bzero(&server_addr, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(MYPORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
- if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
- {
- printf("bind error\n");
- return -1;
- }
-
-
- if(listen(sockListen, 5) < 0)
- {
- printf("listen error\n");
- return -1;
- }
-
-
- epollfd = epoll_create(MAX_EVENTS);
- struct epoll_event event;
- event.events = EPOLLIN|EPOLLET;
- event.data.fd = sockListen;
-
-
- if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockListen, &event) < 0)
- {
- printf("epoll add fail : fd = %d\n", sockListen);
- return -1;
- }
-
-
- while(1)
- {
- timeout=3000;
-
- int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout);
-
- if(ret < 0)
- {
- printf("epoll error\n");
- break;
- }
- else if(ret == 0)
- {
- printf("timeout ...\n");
- continue;
- }
-
-
- int n = 0;
- for(n=0; n
- {
-
- if ((eventList[n].events & EPOLLERR) ||
- (eventList[n].events & EPOLLHUP) ||
- !(eventList[n].events & EPOLLIN))
- {
- printf ( "epoll error\n");
- close (eventList[n].data.fd);
- return -1;
- }
-
- if (eventList[n].data.fd == sockListen)
- {
- AcceptConn(sockListen);
-
- }else{
- RecvData(eventList[n].data.fd);
-
-
- }
- }
- }
-
- close(epollfd);
- close(sockListen);
-
- printf("test\n");
- return 0;
- }
-
-
-
-
-
-
- void AcceptConn(int srvfd)
- {
- struct sockaddr_in sin;
- socklen_t len = sizeof(struct sockaddr_in);
- bzero(&sin, len);
-
- int confd = accept(srvfd, (struct sockaddr*)&sin, &len);
-
- if (confd < 0)
- {
- printf("bad accept\n");
- return;
- }else
- {
- printf("Accept Connection: %d", confd);
- }
-
-
-
-
-
- struct epoll_event event;
- event.data.fd = confd;
- event.events = EPOLLIN|EPOLLET;
- epoll_ctl(epollfd, EPOLL_CTL_ADD, confd, &event);
- }
-
-
- void RecvData(int fd)
- {
- int ret;
- int recvLen = 0;
-
- memset(recvBuf, 0, REVLEN);
- printf("RecvData function\n");
-
- if(recvLen != REVLEN)
- {
- while(1)
- {
-
- ret = recv(fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
- if(ret == 0)
- {
- recvLen = 0;
- break;
- }
- else if(ret < 0)
- {
- recvLen = 0;
- break;
- }
-
- recvLen = recvLen+ret;
- if(recvLen
- {
- continue;
- }
- else
- {
-
- printf("buf = %s\n", recvBuf);
- recvLen = 0;
- break;
- }
- }
- }
-
- printf("content is %s", recvBuf);
- }