send_size = send(connfd, p, remain_size, flag);
if (nSentSize < 0)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR))
{
continue;
}
else
{
len -= remain_size;
return false;
}
}
p += send_size;
remain_size -= send_size;
}while(remain_size > 0);
return true;
}10 epoll 实现服务器和客户端例子
最后我们用C++实现一个简单的客户端回射,所用到的代码文件是
net.h server.cpp client.cpp服务器端:epoll实现的,干两件事分别为:1.等待客户端的链接,2.接收来自客户端的数据并且回射;
客户端:select实现,干两件事为:1.等待键盘输入,2.发送数据到服务器端并且接收服务器端回射的数据;
/***********
net.h
***********/
#include <stdio.h>
#ifndef _NET_H
#define _NET_H
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <sys/types.h>
#include <sys/epoll.h> //epoll ways file
#include <sys/socket.h>
#include <fcntl.h> //block and noblock
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
using namespace std;
#define hand_error(msg) do{perror(msg); exit(EXIT_FAILURE);}while(0)
#endif
/***********
server.c
***********/
#include "net.h"
#define MAX_EVENTS 10000
int setblock(int sock)
{
int ret = fcntl(sock, F_SETFL, 0);
if (ret < 0 )
hand_error("setblock");
return 0;
}
int setnoblock(int sock) //设置非阻塞模式
{
int ret = fcntl(sock, F_SETFL, O_NONBLOCK );
if(ret < 0)
hand_error("setnoblock");
return 0;
}
int main()
{
signal(SIGPIPE,SIG_IGN);
int listenfd;
listenfd = socket( AF_INET, SOCK_STREAM,0 ); //create a socket stream
if( listenfd < 0 )
hand_error( "socket_create");
setnoblock(listenfd);
int on = 1;
if( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))< 0)
hand_error("setsockopt");
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(18000); //here is host sequeue
my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if( bind( listenfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
hand_error("bind");
int lisId = listen(listenfd, SOMAXCONN);
if( lisId < 0) //LISTEN
hand_error("listen");
struct sockaddr_in peer_addr; //用来 save client addr
socklen_t peerlen;
//下面是一些初始化,都是关于epoll的。
vector<int> clients;
int count = 0;
int cli_sock = 0;
int epfd = 0; //epoll 的文件描述符
int ret_events; //epoll_wait()的返回值
struct epoll_event ev_remov, ev, events[MAX_EVENTS]; //events 用来存放从内核读取的的事件
ev.events = EPOLLET | EPOLLIN; //边缘方式触发
ev.data.fd = listenfd;