- 论坛徽章:
- 11
|
[ 本帖最后由 bskay 于 2015-09-02 13:07 编辑 ]
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <cassert>
#include <time.h>
#include <infiniband/verbs.h>
//strerror
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef _DEBUG
#undef _DEBUG
#define _DEBUG(fmt,arg...) {fprintf(stdout, fmt, ##arg);fflush(stdout);}
#define _ERROR(fmt,arg...) {fprintf(stderr, fmt, ##arg);fflush(stderr);}
#define _INFO(fmt,arg...) {fprintf(stderr, fmt, ##arg);fflush(stderr);}
#else
#define _DEBUG(fmt,arg...)
#define _ERROR(fmt,arg...)
#define _INFO(fmt,arg...)
#endif
template<int LEN=128>
class socket_address_storage_policy
{
public:
struct sockaddr& sa()
{
return *reinterpret_cast<struct sockaddr*>(data);
}
int Length()
{
struct sockaddr& addr = sa();
switch (addr.sa_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
break;
case AF_INET6:
return sizeof(struct sockaddr_in6);
break;
case AF_UNIX:
return sizeof(struct sockaddr_un);
break;
default:
return 0;
}
}
static int MaxSize() {return LEN;}
protected:
char data[LEN];
};
template<class TSockAddr>
class socket_address_policy:public socket_address_storage_policy<sizeof(TSockAddr)>
{
public:
typedef TSockAddr c_sockaddr_t;
c_sockaddr_t& Addr()
{
struct sockaddr& addr = this->sa();
return *reinterpret_cast<c_sockaddr_t*>(&addr);
}
};
template<class TSockAddr, class TFd=int>
class socket_func_policy
{
public:
typedef TSockAddr sock_addr_t;
typedef socket_func_policy<TSockAddr, TFd> socket_t;
typedef typename TSockAddr::c_sockaddr_t c_sockaddr_t;
socket_func_policy()
{
fd = -1;
}
~socket_func_policy()
{
Close();
}
bool Socket(int domain, int type, int protocol)
{
if (fd != -1)
return false;
fd = ::socket(domain, type, protocol);
if (fd == -1)
return false;
_DEBUG("socket_func_policy: socket ok (%d)\n",fd);
return true;
}
bool Bind(sock_addr_t& addr)
{
struct sockaddr& csa = addr.sa();
int nCode = ::bind(fd, &csa, addr.Length());
if (nCode != 0)
return false;
_DEBUG("socket_func_policy: bind ok (%d)\n",fd);
return true;
}
bool Listen(int backlog)
{
int nCode = ::listen(fd, backlog);
if (nCode != 0)
return false;
_DEBUG("socket_func_policy: listen ok (%d)\n",fd);
return true;
}
bool Accept(socket_t& peer, sock_addr_t& addr)
{
socklen_t address_len = addr.MaxSize();
peer.fd = ::accept(this->fd, &addr.sa(), &address_len);
if (peer.fd <= 0)
return false;
_DEBUG("socket_func_policy: accept ok (%d)->(%d)\n",fd,peer.fd);
return true;
}
bool Connect(sock_addr_t& addr)
{
if (::connect(fd, &addr.sa(), addr.Length()) != 0)
return false;
_DEBUG("socket_func_policy: connect ok (%d)\n",fd);
return true;
}
bool Close()
{
if (fd == -1)
return false;
if (close(fd) != 0)
return false;
_DEBUG("socket_func_policy: close ok (%d)\n",fd);
fd = -1;
return true;
}
TFd fd;
};
template<class THost>
class unix_domain_serve_policy:
public socket_func_policy<socket_address_policy<struct sockaddr_un> >
{
public:
typedef unix_domain_serve_policy<THost> server_t;
bool Open(const char* szPath, const char* szPort)
{
if (!this->Socket(AF_UNIX, SOCK_STREAM, 0))
{
return false;
}
sock_addr_t addr;
FillAddr(addr, szPath);
if (!this->Bind(addr))
{
_DEBUG("unix_domain_serve_policy: bind error [%s]\n",szPath);
return false;
}
if (!this->Listen(10))
{
_DEBUG("unix_domain_serve_policy: listen error [%s]\n",szPath);
return false;
}
_DEBUG("unix_domain_serve_policy: listen on [%s]\n",szPath);
return true;
}
bool FillAddr(sock_addr_t& addr, const char* szPath)
{
struct sockaddr_un& unAddr = addr.Addr();
unAddr.sun_family = AF_UNIX;
int nLen = sprintf(unAddr.sun_path, szPath)+1;
nLen += sizeof(unAddr.sun_family);
unlink(szPath);
return true;
}
};
template<class THost>
class unix_domain_client_policy:
public socket_func_policy<socket_address_policy<struct sockaddr_un> >
{
public:
typedef unix_domain_client_policy<THost> client_t;
bool Open(const char* szPath, const char* szPort)
{
if (!this->Socket(AF_UNIX, SOCK_STREAM, 0))
return false;
sock_addr_t addr;
FillAddr(addr, szPath);
if (!this->Connect(addr))
{
_DEBUG("unix_domain_client_policy: connect error [%s] %d %s\n",szPath,errno,strerror(errno));
return false;
}
return true;
}
bool FillAddr(sock_addr_t& addr, const char* szPath)
{
struct sockaddr_un& unAddr = addr.Addr();
unAddr.sun_family = AF_UNIX;
int nLen = sprintf(unAddr.sun_path, szPath)+1;
nLen += sizeof(unAddr.sun_family);
//unlink(szPath);
return true;
}
};
template<class THost>
class epoll_policy
{
protected:
typedef epoll_policy<THost> epoll_t;
epoll_policy()
{
epollfd = -1;
}
~epoll_policy()
{
Close();
}
bool Open(int nSize)
{
if (epollfd != -1)
return false;
epollfd = epoll_create(nSize);
if (epollfd == -1)
return false;
_DEBUG("epoll_policy: epollfd = [%d]\n",epollfd);
return true;
}
bool Add(int fd, int event, void* ptr)
{
struct epoll_event ev;
ev.data.ptr = ptr;
ev.events = event;//EPOLLIN EPOLLET;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
return false;
_DEBUG("epoll_policy: EPOLL_CTL_ADD = [%d]\n",fd);
return true;
}
bool Mod(int fd, int event, void* ptr)
{
struct epoll_event ev;
ev.data.ptr = ptr;
ev.events = event;//EPOLLIN EPOLLET;
if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) == -1)
return false;
_DEBUG("epoll_policy: EPOLL_CTL_MOD = [%d]\n",fd);
return true;
}
bool Del(int fd, int event, void* ptr)
{
struct epoll_event ev;
ev.data.ptr = ptr;
ev.events = event;//EPOLLIN EPOLLET;
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev) == -1)
return false;
_DEBUG("epoll_policy: EPOLL_CTL_DEL = [%d]\n",fd);
return true;
}
bool Wait(struct epoll_event *events, int maxevents, int timeout)
{
int nfds = epoll_wait(epollfd, events, maxevents, timeout);
if (nfds < 0)
return false;
//_DEBUG("epoll_policy: epoll_wait = [%d]\n", nfds);
struct epoll_event evNull = {0};
events[nfds] = evNull;
return true;
}
bool Close()
{
if (epollfd == -1)
return false;
if (close(epollfd) != 0)
return false;
epollfd = -1;
return true;
}
int epollfd;
};
template<class THost>
class time_span_policy
{
protected:
typedef time_span_policy<THost> time_span_t;
void reset()
{
begin.tv_sec = 0;
begin.tv_usec = 0;
end = begin;
dlt = begin;
}
void start()
{
gettimeofday(&begin,NULL);
}
void stop()
{
gettimeofday(&end,NULL);
dlt.tv_sec += end.tv_sec - begin.tv_sec;
dlt.tv_usec += end.tv_usec - begin.tv_usec;
}
int mseconds()
{
int ms = dlt.tv_sec*1000 + dlt.tv_usec/1000;
return ms;
}
struct timeval begin;
struct timeval end;
struct timeval dlt;
};
template <
class THost,
template<class>class serve_policy,
template<class>class client_policy
>
class test_socket_policy:
virtual public serve_policy<THost>,
virtual public client_policy<THost>,
public epoll_policy<THost>,
public time_span_policy<THost>
{
public:
typedef typename serve_policy<THost>::server_t server_t;
typedef typename client_policy<THost>::client_t client_t;
typedef typename epoll_policy<THost>::epoll_t epoll_t;
typedef typename time_span_policy<THost>::time_span_t time_span_t;
test_socket_policy(){};
struct PeerInfo
{
typename server_t::socket_t sock;
typename server_t::sock_addr_t addr;
char* buf;
char* buf1;
};
static int main(int argc, char* argv[])
{
THost tuds;
tuds.argc = argc;
tuds.argv = argv;
tuds.nBlock = atoi(argv[4]);
tuds.nTimes = atoi(argv[5]);
tuds.ppi.buf = new char[tuds.nBlock];
tuds.ppi.buf1 = new char[tuds.nBlock];
for (int n=0; n<tuds.nBlock; n++) tuds.ppi.buf[n] = n%256;
if ('A' <= argv[1][0] && argv[1][0] <= 'Z')
return tuds.server();
if ('a' <= argv[1][0] && argv[1][0] <= 'z')
return tuds.client();
delete[] tuds.ppi.buf;
delete[] tuds.ppi.buf1;
return -1;
}
int server()
{
_DEBUG("start unix domain socket server\n");
if (!server_t::Open(argv[2],argv[3]))
return __LINE__;
if (!epoll_t::Open(2))
return __LINE__;
if (!epoll_t::Add(server_t::fd, EPOLLIN, this))
return __LINE__;
struct epoll_event events[2+1];
int timeout = 0;
for (;;)
{
if (!epoll_t::Wait(events, 3, timeout))
return __LINE__;
timeout = 5*1000;
for (int i=0; events[i].data.ptr != NULL; i++)
{
timeout = 0;
if (events[i].data.ptr == this)
{
if (!server_t::Accept(ppi.sock, ppi.addr))
return __LINE__;
if (!epoll_t::Add(ppi.sock.fd, EPOLLIN, &ppi))
return __LINE__;
//ppi.fp = fopen(argv[3], "wb");
if (!epoll_t::Del(server_t::fd, EPOLLIN, this))
return __LINE__;
}
else if (events[i].data.ptr == &ppi)
{
int nLen = recv(ppi.sock.fd, ppi.buf, nBlock, 0);
if (nLen <= 0)
{
//fclose(ppi.fp);
if (!epoll_t::Add(server_t::fd, EPOLLIN, this))
return __LINE__;
if (!epoll_t::Del(ppi.sock.fd, 0, NULL))
return __LINE__;
ppi.sock.Close();
}
else
{
//fwrite(ppi.buf, sizeof(char), nLen, ppi.fp);
}
}
else
{
return __LINE__;
}
}
}
return 0;
}
int client()
{
_DEBUG("start unix domain socket client\n");
if (!client_t::Open(argv[2],argv[3]))
return __LINE__;
time_span_t::reset();
time_span_t::start();
//ppi.fp = fopen(argv[3], "rb");
//if (ppi.fp == NULL)
// return __LINE__;
if (!epoll_t::Open(1))
return __LINE__;
if (!epoll_t::Add(client_t::fd, EPOLLIN|EPOLLOUT, this))
return __LINE__;
struct epoll_event events[1+1];
int timeout = 0;
for (;;)
{
if (!epoll_t::Wait(events, 2, timeout))
return __LINE__;
timeout = 1000;
for (int i=0; events[i].data.ptr != NULL; i++)
{
timeout = 0;
if (events[i].data.ptr == this)
{
if ((events[i].events&EPOLLOUT) != 0)
{
//int nLen = fread(ppi.buf, sizeof(char), sizeof(ppi.buf), ppi.fp);
int nLen = nBlock;
if (nLen > 0)
{
int nSend = send(client_t::fd, ppi.buf, nLen, 0);
//memcpy(ppi.buf1,ppi.buf,nLen);
//memcpy(ppi.buf,ppi.buf1,nLen);
//int nSend = nLen;
if (nSend != nLen)
{
_DEBUG("client socket send(%d) != %d\n",nLen, nSend);
return __LINE__;
}
nTimes--;
}
if (nTimes == 0)
{
client_t::Close();
time_span_t::stop();
_DEBUG("client timespan=%d\n", time_span_t::mseconds());
return 0;
}
}
}
else
{
return __LINE__;
}
}
}
_DEBUG("client end\n");
return __LINE__;
}
int argc;
char** argv;
PeerInfo ppi;
int nBlock;
int nTimes;
};
template<class THost>
class ipv4_serve_policy:
public socket_func_policy<socket_address_policy<struct sockaddr_in> >
{
public:
typedef ipv4_serve_policy<THost> server_t;
bool Open(const char* szPath, const char* szPort)
{
if (!this->Socket(AF_INET, SOCK_STREAM, 0))
{
return false;
}
sock_addr_t addr;
FillAddr(addr, szPath, szPort);
if (!this->Bind(addr))
{
_DEBUG("ipv4_serve_policy: bind error [%s]\n",szPath);
return false;
}
if (!this->Listen(10))
{
_DEBUG("ipv4_serve_policy: listen error [%s]\n",szPath);
return false;
}
_DEBUG("ipv4_serve_policy: listen on [%s:%s]\n",szPath,szPort);
return true;
}
bool FillAddr(sock_addr_t& addr, const char* szPath, const char* szPort)
{
struct sockaddr_in& unAddr = addr.Addr();
unAddr.sin_family = AF_INET;
int nCode = inet_pton(AF_INET, szPath, &unAddr.sin_addr);
if (nCode <= 0)
return false;
unAddr.sin_port = ntohs(atoi(szPort));
return true;
}
};
template<class THost>
class ipv4_client_policy:
public socket_func_policy<socket_address_policy<struct sockaddr_in> >
{
public:
typedef ipv4_client_policy<THost> client_t;
bool Open(const char* szPath, const char* szPort)
{
if (!this->Socket(AF_INET, SOCK_STREAM, 0))
return false;
sock_addr_t addr;
FillAddr(addr, szPath, szPort);
if (!this->Connect(addr))
{
_DEBUG("ipv4_client_policy: connect error [%s:%s] %d %s\n",szPath,szPort,errno,strerror(errno));
return false;
}
return true;
}
bool FillAddr(sock_addr_t& addr, const char* szPath, const char* szPort)
{
struct sockaddr_in& unAddr = addr.Addr();
unAddr.sin_family = AF_INET;
int nCode = inet_pton(AF_INET, szPath, &unAddr.sin_addr);
if (nCode <= 0)
return false;
unAddr.sin_port = ntohs(atoi(szPort));
return true;
}
};
class TestUnixDomainSocket:
public test_socket_policy<
TestUnixDomainSocket,
unix_domain_serve_policy,
unix_domain_client_policy>
{
};
class TestIpv4Socket:
public test_socket_policy<
TestIpv4Socket,
ipv4_serve_policy,
ipv4_client_policy>
{
};
int main(int argc, char* argv[], char* env[])
{
/*
argv[0] U /tmp/.unix.domain.path port block times
argv[0] u /tmp/.unix.domain.path port block times
argv[0] S ip port block times
argv[0] s ip port block times
*/
if (argc <= 2)
{
return -1;
}
if (argv[1][0] == 'U' || argv[1][0] == 'u')
{
TestUnixDomainSocket::main(argc, argv);
}
else if (argv[1][0] == 'S' || argv[1][0] == 's')
{
TestIpv4Socket::main(argc, argv);
}
return 0;
}
[/i][/i][/i][/i][/i][/i] |
|