网络程序为了支持并发,可以采用select,多线程等技术.
但是对于select,readhat linux系统只支持最大1024个描述符.
因此要想同时并发超过1024,就无法使用select模式.
而使用多线程,并发数达到1000时将严重影响系统的性能.
而使用epoll可以避免以上的缺陷.
下面是一个使用epoll实现客户端UDP并发.是我为写压力测试程序而写的.
发送使用一个独立的线程,接收使用epoll调用.
在程序开始要先设置系统能打开的最大描述符限制.即setrlimt调用.
在linux readhat enterprise 4环境下测试通过。其它环境我没测过。
g++ -oudp_epoll_c udp_epoll_c.cpp -lpthread
CODE:
/***************************************************************************
file: udp_epoll_c.cpp
-------------------
begin : 2006/01/17
copyright : (C) 2005 by 张荐林
email : zhangjianlin_8 at 126.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify*
* it under the terms of the GNU General Public License as published by*
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <errno.h>
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <sys/resource.h>
#include <pthread.h>
#include <vector>
using namespace std;
int Read(int fd,void *buffer,unsigned int length)
{
unsigned int nleft;
int nread;
char *ptr;
ptr = (char *)buffer;
nleft = length;
while(nleft > 0)
{
if((nread = read(fd, ptr, nleft))< 0)
{
if(errno == EINTR)
nread = 0;
else
return -1;
}
else if(nread == 0)
{
break;
}
nleft -= nread;
ptr += nread;
}
return length - nleft;
}
int Write(int fd,const void *buffer,unsigned int length)
{
unsigned int nleft;
int nwritten;
const char *ptr;
ptr = (const char *)buffer;
nleft = length;
while(nleft > 0)
{
if((nwritten = write(fd, ptr, nleft))<=0)
{
if(errno == EINTR)
nwritten=0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return length;
}
int CreateThread(void *(*start_routine)(void *), void *arg = NULL, pthread_t *thread = NULL, pthread_attr_t *pAttr = NULL)
{
pthread_attr_t thr_attr;
if(pAttr == NULL)
{
pAttr = &thr_attr;
pthread_attr_init(pAttr);
pthread_attr_setstacksize(pAttr, 1024 * 1024);// 1 M的堆栈
pthread_attr_setdetachstate(pAttr,PTHREAD_CREATE_DETACHED);
}
pthread_t tid;
if(thread == NULL)
{
thread = &tid;
}
int r = pthread_create(thread, pAttr, start_routine, arg);
pthread_attr_destroy(pAttr);
return r;
}
static int SetRLimit()
{
struct rlimit rlim;
rlim.rlim_cur = 20480;
rlim.rlim_max = 20480;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0)
{
perror("setrlimit");
}
else
{
printf("setrlimit ok/n");
}
return 0;
}
int setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);
if(opts<0)
{
return -1;
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
return -1;
}
return 0;
}
int ConnectToUdperver(const char *host, unsigned short port)
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
perror("socket");
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(host);
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
close(sock);
return -1;
}
return sock;
}
void *SendThread(void *arg)
{
vector<int> sockets;
sockets = *((vector<int> *)arg);
int n = 0;
char data[1024];
int i = 0;
while(1)
{
for(vector<int>::iterator itr = sockets.begin(), last = sockets.end(); itr != last; ++itr)
{
sprintf(data, "test data %d/n", i++);
n = Write(*itr, "hello", 5);
printf("socket %d write to server[ret = %d]:%s",*itr, n, data);
}
sleep(1);
}
}
int main(int argc, char **argv)
{
SetRLimit();
printf("FD_SETSIZE= %d/n", FD_SETSIZE);
if (argc != 3)
{
printf("usage: %s <IPaddress> <PORT>/n", argv[0]);
return 1;
}
int epfd = epoll_create(20480);
if(epfd < 0)
{
perror("epoll_create");
return 1;
}
struct epoll_event event;
struct epoll_event ev[20480];
vector<int> sockets;
for(int i = 0; i < 3000; i++)
{
int sockfd = ConnectToUdperver(argv[1], (unsigned short)(atoi(argv[2])));
if(sockfd < 0)
{
printf("Cannot connect udp server %s %s/n", argv[1], argv[2]);
return 1;
}
sockets.push_back(sockfd);
setnonblocking(sockfd);
event.data.fd = sockfd;
event.events = EPOLLIN|EPOLLET;
if(0 != epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&event))
{
perror("epoll_ctl");
}
}
if(0 != CreateThread(SendThread, (void *)&sockets))
{
perror("CreateThread");
return 2;
}
int nfds = 0;
while(1)
{
nfds=epoll_wait(epfd,ev,20480,500);
if(nfds < 0)
{
perror("epoll_wait");
break;
}
else if(nfds == 0)
{
printf("epoll_wait timeout!/n");
continue;
}
for(int i = 0; i < nfds; i++)
{
if(ev[i].events & EPOLLIN)
{
printf("can read for %d now/n", ev[i].data.fd);
char data[1024] = {0};
int n = read(ev[i].data.fd, data, sizeof(data));
printf("Received %d bytes from server!/n", n);
}
}
}
for(vector<int>::iterator itr = sockets.begin(), last = sockets.end(); itr != last; itr++)
{
close(*itr);
}
close(epfd);
return 0;
}
分享到:
相关推荐
课程介绍 ⽹络概述、udp ⽹络通信概述 tcp/ip简介 端⼝ ...并发服务器、HTTP协议 单进程服务器 多进程服务器 多线程服务器 单进程服务器-⾮堵塞模式 单进程服务器-select版 单进程服务器-epoll版 多任务实现-协程
使用epoll+线程池+异步网络IO模式开发,并发性能优越。 代码经过大量的稳定性、性能测试,可满足商用服务器项目。 支持linux、macos、ios、android、windows平台 特性: 网络库 tcp/udp客户端,接口简单易用并且是...
使用epoll+线程池+异步网络IO模式开发,并发性能优越。代码经过大量的稳定性、性能测试,可满足商用服务器项目。支持linux、macos、ios、android、windows平台了解更多:特性网络库tcp/udp客户端,接口简单易用并且是...
21、Linux网络编程——tcp高效并发服务器(epoll实现) 二、网络底层编程(黑客模式) 1、Linux网络编程1——啥叫原始套接字 2、Linux网络编程2——原始套接字编程 3、Linux网络编程3——原始套接字实例:MAC头分析 ...
mushroom支持TCP、UDP通信,让客户端非常容易创建并发网络链接,可以让手机快速创建上万条链接,甚至可以让手机作为服务器,被上万客户端连接。 mushroom还有另外一个分支mushroom-kcp,mushroom-kcp在UDP的基础上,...
服务器基于IOCP / EPOLL通信模型,结合内存池,私有堆等技术,实现了高效的内存管理,以支持大规模和高并发通信场景。 代理代理组件本质上是一个多客户端组件,它使用与服务器组件相同的技术体系结构。 Agent组件...
为您提供HP-Socket通信框架下载,HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端...特点:Server基于IOCP / EPOLL通信模型,并结合缓存池、私有堆等技术实现高效内存管理,支持超大规模、高并发通
基于IOCP / EPOLL通信模型,并结合缓存池、私有堆等技术实现高效内存管理,支持超大规模、高并发通信场景。 Agent Agent组件实质上是Multi-Client组件,与Server组件采用相同的技术架构。一个Agent组件对象可同时...
09 select与epoll的实现区别 第36章 01 异步IO 02 selectors模块介绍 03 selectors模块应用 04 作业介绍 第37章 01 selctors实现文件上传与下载 02 html的介绍 03 html文档树的概念 04 meta标签以及一些基本标签...
聊天室程序 9.6.1 客户端 9.6.2 服务器 9.7 IO复用的高级应用三:同时处理TCP和UDP服务 9.8 超级服务xinetd 9.8.1 xinetd配置文件 9.8.2 xinetd工作流程 第10章 信号 10.1 Linux信号概述 10.1.1 发送信号 ...
其Server 组件:基于IOCP / EPOLL通信模型,并结合缓存池、私有堆等技术实现高效内存管理,支持超大规模、高并发通信场景。 应用程序能够根据不同的容量要求、通信规模和资源状况等现实场景调整 HP-Socket 的各项...